home *** CD-ROM | disk | FTP | other *** search
/ Freelog 115 / FreelogNo115-MaiJuin2013.iso / Internet / AvantBrowser / asetup.exe / _data / webkit / resources.pak / Unnamed File 000118.unknown < prev    next >
Text File  |  2013-04-03  |  257KB  |  9,355 lines

  1.  
  2.  
  3.  
  4. const UserInitiatedProfileName = "org.webkit.profiles.user-initiated";
  5.  
  6.  
  7. WebInspector.ProfileType = function(id, name)
  8. {
  9. this._id = id;
  10. this._name = name;
  11.  
  12. this.treeElement = null;
  13. }
  14.  
  15. WebInspector.ProfileType.prototype = {
  16. get buttonTooltip()
  17. {
  18. return "";
  19. },
  20.  
  21. get id()
  22. {
  23. return this._id;
  24. },
  25.  
  26. get treeItemTitle()
  27. {
  28. return this._name;
  29. },
  30.  
  31. get name()
  32. {
  33. return this._name;
  34. },
  35.  
  36.  
  37. buttonClicked: function(profilesPanel)
  38. {
  39. return false;
  40. },
  41.  
  42. reset: function()
  43. {
  44. },
  45.  
  46. get description()
  47. {
  48. return "";
  49. },
  50.  
  51.  
  52.  
  53. createTemporaryProfile: function(title)
  54. {
  55. throw new Error("Needs implemented.");
  56. },
  57.  
  58.  
  59. createProfile: function(profile)
  60. {
  61. throw new Error("Not supported for " + this._name + " profiles.");
  62. }
  63. }
  64.  
  65.  
  66. WebInspector.ProfileHeader = function(profileType, title, uid)
  67. {
  68. this._profileType = profileType;
  69. this.title = title;
  70. if (uid === undefined) {
  71. this.uid = -1;
  72. this.isTemporary = true;
  73. } else {
  74. this.uid = uid;
  75. this.isTemporary = false;
  76. }
  77. this._fromFile = false;
  78. }
  79.  
  80. WebInspector.ProfileHeader.prototype = {
  81.  
  82. profileType: function()
  83. {
  84. return this._profileType;
  85. },
  86.  
  87.  
  88. createSidebarTreeElement: function()
  89. {
  90. throw new Error("Needs implemented.");
  91. },
  92.  
  93.  
  94. existingView: function()
  95. {
  96. return this._view;
  97. },
  98.  
  99.  
  100. view: function()
  101. {
  102. if (!this._view)
  103. this._view = this.createView(WebInspector.ProfilesPanel._instance);
  104. return this._view;
  105. },
  106.  
  107.  
  108. createView: function(profilesPanel)
  109. {
  110. throw new Error("Not implemented.");
  111. },
  112.  
  113.  
  114. load: function(callback) { },
  115.  
  116.  
  117. canSaveToFile: function() { return false; },
  118.  
  119. saveToFile: function() { throw new Error("Needs implemented"); },
  120.  
  121.  
  122. canLoadFromFile: function() { return false; },
  123.  
  124.  
  125. loadFromFile: function(file) { throw new Error("Needs implemented"); },
  126.  
  127.  
  128. fromFile: function() { return this._fromFile; }
  129. }
  130.  
  131.  
  132. WebInspector.ProfilesPanel = function()
  133. {
  134. WebInspector.Panel.call(this, "profiles");
  135. WebInspector.ProfilesPanel._instance = this;
  136. this.registerRequiredCSS("panelEnablerView.css");
  137. this.registerRequiredCSS("heapProfiler.css");
  138. this.registerRequiredCSS("profilesPanel.css");
  139.  
  140. this.createSidebarViewWithTree();
  141.  
  142. this.profilesItemTreeElement = new WebInspector.ProfilesSidebarTreeElement(this);
  143. this.sidebarTree.appendChild(this.profilesItemTreeElement);
  144.  
  145. this._profileTypesByIdMap = {};
  146.  
  147. var panelEnablerHeading = WebInspector.UIString("You need to enable profiling before you can use the Profiles panel.");
  148. var panelEnablerDisclaimer = WebInspector.UIString("Enabling profiling will make scripts run slower.");
  149. var panelEnablerButton = WebInspector.UIString("Enable Profiling");
  150. this.panelEnablerView = new WebInspector.PanelEnablerView("profiles", panelEnablerHeading, panelEnablerDisclaimer, panelEnablerButton);
  151. this.panelEnablerView.addEventListener("enable clicked", this.enableProfiler, this);
  152.  
  153. this.profileViews = document.createElement("div");
  154. this.profileViews.id = "profile-views";
  155. this.splitView.mainElement.appendChild(this.profileViews);
  156.  
  157. this._statusBarButtons = [];
  158.  
  159. this.enableToggleButton = new WebInspector.StatusBarButton("", "enable-toggle-status-bar-item");
  160. if (Capabilities.profilerCausesRecompilation) {
  161. this._statusBarButtons.push(this.enableToggleButton);
  162. this.enableToggleButton.addEventListener("click", this._onToggleProfiling, this);
  163. }
  164. this.recordButton = new WebInspector.StatusBarButton("", "record-profile-status-bar-item");
  165. this.recordButton.addEventListener("click", this.toggleRecordButton, this);
  166. this._statusBarButtons.push(this.recordButton);
  167.  
  168. this.clearResultsButton = new WebInspector.StatusBarButton(WebInspector.UIString("Clear all profiles."), "clear-status-bar-item");
  169. this.clearResultsButton.addEventListener("click", this._clearProfiles, this);
  170. this._statusBarButtons.push(this.clearResultsButton);
  171.  
  172. if (WebInspector.experimentsSettings.liveNativeMemoryChart.isEnabled()) {
  173. this.garbageCollectButton = new WebInspector.StatusBarButton(WebInspector.UIString("Collect Garbage"), "garbage-collect-status-bar-item");
  174. this.garbageCollectButton.addEventListener("click", this._garbageCollectButtonClicked, this);
  175. this._statusBarButtons.push(this.garbageCollectButton);
  176. }
  177.  
  178. this.profileViewStatusBarItemsContainer = document.createElement("div");
  179. this.profileViewStatusBarItemsContainer.className = "status-bar-items";
  180.  
  181. this._profiles = [];
  182. this._profilerEnabled = !Capabilities.profilerCausesRecompilation;
  183.  
  184. this._launcherView = new WebInspector.ProfileLauncherView(this);
  185. this._launcherView.addEventListener(WebInspector.ProfileLauncherView.EventTypes.ProfileTypeSelected, this._onProfileTypeSelected, this);
  186. this._reset();
  187.  
  188. this._registerProfileType(new WebInspector.CPUProfileType());
  189. if (!WebInspector.WorkerManager.isWorkerFrontend())
  190. this._registerProfileType(new WebInspector.CSSSelectorProfileType());
  191. if (Capabilities.heapProfilerPresent)
  192. this._registerProfileType(new WebInspector.HeapSnapshotProfileType());
  193. if (WebInspector.experimentsSettings.nativeMemorySnapshots.isEnabled())
  194. this._registerProfileType(new WebInspector.NativeMemoryProfileType());
  195. if (WebInspector.experimentsSettings.canvasInspection.isEnabled())
  196. this._registerProfileType(new WebInspector.CanvasProfileType());
  197.  
  198. InspectorBackend.registerProfilerDispatcher(new WebInspector.ProfilerDispatcher(this));
  199.  
  200. this._createFileSelectorElement();
  201. this.element.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), true);
  202.  
  203. WebInspector.ContextMenu.registerProvider(this);
  204. }
  205.  
  206. WebInspector.ProfilesPanel.prototype = {
  207. _createFileSelectorElement: function()
  208. {
  209. if (this._fileSelectorElement)
  210. this.element.removeChild(this._fileSelectorElement);
  211. this._fileSelectorElement = WebInspector.createFileSelectorElement(this._loadFromFile.bind(this));
  212. this.element.appendChild(this._fileSelectorElement);
  213. },
  214.  
  215.  
  216. _loadFromFile: function(file)
  217. {
  218. if (!file.name.endsWith(".heapsnapshot")) {
  219. WebInspector.log(WebInspector.UIString("Only heap snapshots from files with extension '.heapsnapshot' can be loaded."));
  220. return;
  221. }
  222.  
  223. if (!!this.findTemporaryProfile(WebInspector.HeapSnapshotProfileType.TypeId)) {
  224. WebInspector.log(WebInspector.UIString("Can't load profile when other profile is recording."));
  225. return;
  226. }
  227.  
  228. var profileType = this.getProfileType(WebInspector.HeapSnapshotProfileType.TypeId);
  229. var temporaryProfile = profileType.createTemporaryProfile(UserInitiatedProfileName + "." + file.name);
  230. this.addProfileHeader(temporaryProfile);
  231.  
  232. temporaryProfile._fromFile = true;
  233. temporaryProfile.loadFromFile(file);
  234. this._createFileSelectorElement();
  235. },
  236.  
  237. get statusBarItems()
  238. {
  239. return this._statusBarButtons.select("element").concat([this.profileViewStatusBarItemsContainer]);
  240. },
  241.  
  242. toggleRecordButton: function()
  243. {
  244. var isProfiling = this._selectedProfileType.buttonClicked(this);
  245. this.recordButton.toggled = isProfiling;
  246. this.recordButton.title = this._selectedProfileType.buttonTooltip;
  247. if (isProfiling)
  248. this._launcherView.profileStarted();
  249. else
  250. this._launcherView.profileFinished();
  251. },
  252.  
  253. wasShown: function()
  254. {
  255. WebInspector.Panel.prototype.wasShown.call(this);
  256. this._populateProfiles();
  257. },
  258.  
  259. _profilerWasEnabled: function()
  260. {
  261. if (this._profilerEnabled)
  262. return;
  263.  
  264. this._profilerEnabled = true;
  265.  
  266. this._reset();
  267. if (this.isShowing())
  268. this._populateProfiles();
  269. },
  270.  
  271. _profilerWasDisabled: function()
  272. {
  273. if (!this._profilerEnabled)
  274. return;
  275.  
  276. this._profilerEnabled = false;
  277. this._reset();
  278. },
  279.  
  280.  
  281. _onProfileTypeSelected: function(event)
  282. {
  283. this._selectedProfileType =   (event.data);
  284. this.recordButton.title = this._selectedProfileType.buttonTooltip;
  285. },
  286.  
  287. _reset: function()
  288. {
  289. WebInspector.Panel.prototype.reset.call(this);
  290.  
  291. for (var i = 0; i < this._profiles.length; ++i) {
  292. var view = this._profiles[i].existingView();
  293. if (view) {
  294. view.detach();
  295. if ("dispose" in view)
  296. view.dispose();
  297. }
  298. }
  299. delete this.visibleView;
  300.  
  301. delete this.currentQuery;
  302. this.searchCanceled();
  303.  
  304. for (var id in this._profileTypesByIdMap) {
  305. var profileType = this._profileTypesByIdMap[id];
  306. var treeElement = profileType.treeElement;
  307. treeElement.removeChildren();
  308. treeElement.hidden = true;
  309. profileType.reset();
  310. }
  311.  
  312. this._profiles = [];
  313. this._profilesIdMap = {};
  314. this._profileGroups = {};
  315. this._profileGroupsForLinks = {};
  316. this._profilesWereRequested = false;
  317. this.recordButton.toggled = false;
  318. if (this._selectedProfileType)
  319. this.recordButton.title = this._selectedProfileType.buttonTooltip;
  320. this._launcherView.profileFinished();
  321.  
  322. this.sidebarTreeElement.removeStyleClass("some-expandable");
  323.  
  324. this.profileViews.removeChildren();
  325. this.profileViewStatusBarItemsContainer.removeChildren();
  326.  
  327. this.removeAllListeners();
  328.  
  329. this._updateInterface();
  330. this.profilesItemTreeElement.select();
  331. this._showLauncherView();
  332. },
  333.  
  334. _showLauncherView: function()
  335. {
  336. this.closeVisibleView();
  337. this.profileViewStatusBarItemsContainer.removeChildren();
  338. this._launcherView.show(this.splitView.mainElement);
  339. this.visibleView = this._launcherView;
  340. },
  341.  
  342. _clearProfiles: function()
  343. {
  344. ProfilerAgent.clearProfiles();
  345. this._reset();
  346. },
  347.  
  348. _garbageCollectButtonClicked: function()
  349. {
  350. ProfilerAgent.collectGarbage();
  351. },
  352.  
  353.  
  354. _registerProfileType: function(profileType)
  355. {
  356. this._profileTypesByIdMap[profileType.id] = profileType;
  357. this._launcherView.addProfileType(profileType);
  358. profileType.treeElement = new WebInspector.SidebarSectionTreeElement(profileType.treeItemTitle, null, true);
  359. profileType.treeElement.hidden = true;
  360. this.sidebarTree.appendChild(profileType.treeElement);
  361. profileType.treeElement.childrenListElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), true);
  362. },
  363.  
  364.  
  365. _handleContextMenuEvent: function(event)
  366. {
  367. var element = event.srcElement;
  368. while (element && !element.treeElement && element !== this.element)
  369. element = element.parentElement;
  370. if (!element)
  371. return;
  372. if (element.treeElement && element.treeElement.handleContextMenuEvent) {
  373. element.treeElement.handleContextMenuEvent(event);
  374. return;
  375. }
  376. if (element !== this.element || event.srcElement === this.sidebarElement) {
  377. var contextMenu = new WebInspector.ContextMenu(event);
  378. if (this.visibleView instanceof WebInspector.HeapSnapshotView)
  379. this.visibleView.populateContextMenu(contextMenu, event);
  380. contextMenu.appendItem(WebInspector.UIString("Load Heap Snapshot\u2026"), this._fileSelectorElement.click.bind(this._fileSelectorElement));
  381. contextMenu.show();
  382. }
  383.  
  384. },
  385.  
  386.  
  387. _makeTitleKey: function(text, profileTypeId)
  388. {
  389. return escape(text) + '/' + escape(profileTypeId);
  390. },
  391.  
  392.  
  393. _makeKey: function(id, profileTypeId)
  394. {
  395. return id + '/' + escape(profileTypeId);
  396. },
  397.  
  398.  
  399. addProfileHeader: function(profile)
  400. {
  401. this._removeTemporaryProfile(profile.profileType().id);
  402.  
  403. var profileType = profile.profileType();
  404. var typeId = profileType.id;
  405. var sidebarParent = profileType.treeElement;
  406. sidebarParent.hidden = false;
  407. var small = false;
  408. var alternateTitle;
  409.  
  410. this._profiles.push(profile);
  411. this._profilesIdMap[this._makeKey(profile.uid, typeId)] = profile;
  412.  
  413. if (!profile.title.startsWith(UserInitiatedProfileName)) {
  414. var profileTitleKey = this._makeTitleKey(profile.title, typeId);
  415. if (!(profileTitleKey in this._profileGroups))
  416. this._profileGroups[profileTitleKey] = [];
  417.  
  418. var group = this._profileGroups[profileTitleKey];
  419. group.push(profile);
  420.  
  421. if (group.length === 2) {
  422.  
  423. group._profilesTreeElement = new WebInspector.ProfileGroupSidebarTreeElement(profile.title);
  424.  
  425.  
  426. var index = sidebarParent.children.indexOf(group[0]._profilesTreeElement);
  427. sidebarParent.insertChild(group._profilesTreeElement, index);
  428.  
  429.  
  430. var selected = group[0]._profilesTreeElement.selected;
  431. sidebarParent.removeChild(group[0]._profilesTreeElement);
  432. group._profilesTreeElement.appendChild(group[0]._profilesTreeElement);
  433. if (selected)
  434. group[0]._profilesTreeElement.revealAndSelect();
  435.  
  436. group[0]._profilesTreeElement.small = true;
  437. group[0]._profilesTreeElement.mainTitle = WebInspector.UIString("Run %d", 1);
  438.  
  439. this.sidebarTreeElement.addStyleClass("some-expandable");
  440. }
  441.  
  442. if (group.length >= 2) {
  443. sidebarParent = group._profilesTreeElement;
  444. alternateTitle = WebInspector.UIString("Run %d", group.length);
  445. small = true;
  446. }
  447. }
  448.  
  449. var profileTreeElement = profile.createSidebarTreeElement();
  450. profile.sidebarElement = profileTreeElement;
  451. profileTreeElement.small = small;
  452. if (alternateTitle)
  453. profileTreeElement.mainTitle = alternateTitle;
  454. profile._profilesTreeElement = profileTreeElement;
  455.  
  456. sidebarParent.appendChild(profileTreeElement);
  457. if (!profile.isTemporary) {
  458. if (!this.visibleView)
  459. this.showProfile(profile);
  460. this.dispatchEventToListeners("profile added", {
  461. type: typeId
  462. });
  463. }
  464. },
  465.  
  466.  
  467. _removeProfileHeader: function(profile)
  468. {
  469. var sidebarParent = profile.profileType().treeElement;
  470.  
  471. for (var i = 0; i < this._profiles.length; ++i) {
  472. if (this._profiles[i].uid === profile.uid) {
  473. profile = this._profiles[i];
  474. this._profiles.splice(i, 1);
  475. break;
  476. }
  477. }
  478. delete this._profilesIdMap[this._makeKey(profile.uid, profile.profileType().id)];
  479.  
  480. var profileTitleKey = this._makeTitleKey(profile.title, profile.profileType().id);
  481. delete this._profileGroups[profileTitleKey];
  482.  
  483. sidebarParent.removeChild(profile._profilesTreeElement);
  484.  
  485. if (!profile.isTemporary)
  486. ProfilerAgent.removeProfile(profile.profileType().id, profile.uid);
  487.  
  488.  
  489.  
  490. if (!this._profiles.length)
  491. this.closeVisibleView();
  492. },
  493.  
  494.  
  495. showProfile: function(profile)
  496. {
  497. if (!profile || profile.isTemporary)
  498. return;
  499.  
  500. var view = profile.view();
  501. if (view === this.visibleView)
  502. return;
  503.  
  504. this.closeVisibleView();
  505.  
  506. view.show(this.profileViews);
  507.  
  508. profile._profilesTreeElement._suppressOnSelect = true;
  509. profile._profilesTreeElement.revealAndSelect();
  510. delete profile._profilesTreeElement._suppressOnSelect;
  511.  
  512. this.visibleView = view;
  513.  
  514. this.profileViewStatusBarItemsContainer.removeChildren();
  515.  
  516. var statusBarItems = view.statusBarItems;
  517. if (statusBarItems)
  518. for (var i = 0; i < statusBarItems.length; ++i)
  519. this.profileViewStatusBarItemsContainer.appendChild(statusBarItems[i]);
  520. },
  521.  
  522.  
  523. getProfiles: function(typeId)
  524. {
  525. var result = [];
  526. var profilesCount = this._profiles.length;
  527. for (var i = 0; i < profilesCount; ++i) {
  528. var profile = this._profiles[i];
  529. if (!profile.isTemporary && profile.profileType().id === typeId)
  530. result.push(profile);
  531. }
  532. return result;
  533. },
  534.  
  535.  
  536. showObject: function(snapshotObjectId, viewName)
  537. {
  538. var heapProfiles = this.getProfiles(WebInspector.HeapSnapshotProfileType.TypeId);
  539. for (var i = 0; i < heapProfiles.length; i++) {
  540. var profile = heapProfiles[i];
  541.  
  542. if (profile.maxJSObjectId >= snapshotObjectId) {
  543. this.showProfile(profile);
  544. profile.view().changeView(viewName, function() {
  545. profile.view().dataGrid.highlightObjectByHeapSnapshotId(snapshotObjectId);
  546. });
  547. break;
  548. }
  549. }
  550. },
  551.  
  552.  
  553. findTemporaryProfile: function(typeId)
  554. {
  555. var profilesCount = this._profiles.length;
  556. for (var i = 0; i < profilesCount; ++i)
  557. if (this._profiles[i].profileType().id === typeId && this._profiles[i].isTemporary)
  558. return this._profiles[i];
  559. return null;
  560. },
  561.  
  562.  
  563. _removeTemporaryProfile: function(typeId)
  564. {
  565. var temporaryProfile = this.findTemporaryProfile(typeId);
  566. if (temporaryProfile)
  567. this._removeProfileHeader(temporaryProfile);
  568. },
  569.  
  570.  
  571. getProfile: function(typeId, uid)
  572. {
  573. return this._profilesIdMap[this._makeKey(uid, typeId)];
  574. },
  575.  
  576.  
  577. _addHeapSnapshotChunk: function(uid, chunk)
  578. {
  579. var profile = this._profilesIdMap[this._makeKey(uid, WebInspector.HeapSnapshotProfileType.TypeId)];
  580. if (!profile)
  581. return;
  582. profile.transferChunk(chunk);
  583. },
  584.  
  585.  
  586. _finishHeapSnapshot: function(uid)
  587. {
  588. var profile = this._profilesIdMap[this._makeKey(uid, WebInspector.HeapSnapshotProfileType.TypeId)];
  589. if (!profile)
  590. return;
  591. profile.finishHeapSnapshot();
  592. },
  593.  
  594.  
  595. showView: function(view)
  596. {
  597. this.showProfile(view.profile);
  598. },
  599.  
  600.  
  601. getProfileType: function(typeId)
  602. {
  603. return this._profileTypesByIdMap[typeId];
  604. },
  605.  
  606.  
  607. showProfileForURL: function(url)
  608. {
  609. var match = url.match(WebInspector.ProfileURLRegExp);
  610. if (!match)
  611. return;
  612. this.showProfile(this._profilesIdMap[this._makeKey(Number(match[3]), match[1])]);
  613. },
  614.  
  615. closeVisibleView: function()
  616. {
  617. if (this.visibleView)
  618. this.visibleView.detach();
  619. delete this.visibleView;
  620. },
  621.  
  622.  
  623. displayTitleForProfileLink: function(title, typeId)
  624. {
  625. title = unescape(title);
  626. if (title.startsWith(UserInitiatedProfileName)) {
  627. title = WebInspector.UIString("Profile %d", title.substring(UserInitiatedProfileName.length + 1));
  628. } else {
  629. var titleKey = this._makeTitleKey(title, typeId);
  630. if (!(titleKey in this._profileGroupsForLinks))
  631. this._profileGroupsForLinks[titleKey] = 0;
  632.  
  633. var groupNumber = ++this._profileGroupsForLinks[titleKey];
  634.  
  635. if (groupNumber > 2)
  636.  
  637.  
  638. title += " " + WebInspector.UIString("Run %d", (groupNumber + 1) / 2);
  639. }
  640.  
  641. return title;
  642. },
  643.  
  644.  
  645. performSearch: function(query)
  646. {
  647. this.searchCanceled();
  648.  
  649. var searchableViews = this._searchableViews();
  650. if (!searchableViews || !searchableViews.length)
  651. return;
  652.  
  653. var visibleView = this.visibleView;
  654.  
  655. var matchesCountUpdateTimeout = null;
  656.  
  657. function updateMatchesCount()
  658. {
  659. WebInspector.searchController.updateSearchMatchesCount(this._totalSearchMatches, this);
  660. WebInspector.searchController.updateCurrentMatchIndex(this._currentSearchResultIndex, this);
  661. matchesCountUpdateTimeout = null;
  662. }
  663.  
  664. function updateMatchesCountSoon()
  665. {
  666. if (matchesCountUpdateTimeout)
  667. return;
  668.  
  669. matchesCountUpdateTimeout = setTimeout(updateMatchesCount.bind(this), 500);
  670. }
  671.  
  672. function finishedCallback(view, searchMatches)
  673. {
  674. if (!searchMatches)
  675. return;
  676.  
  677. this._totalSearchMatches += searchMatches;
  678. this._searchResults.push(view);
  679.  
  680. if (this.searchMatchFound)
  681. this.searchMatchFound(view, searchMatches);
  682.  
  683. updateMatchesCountSoon.call(this);
  684.  
  685. if (view === visibleView)
  686. view.jumpToFirstSearchResult();
  687. }
  688.  
  689. var i = 0;
  690. var panel = this;
  691. var boundFinishedCallback = finishedCallback.bind(this);
  692. var chunkIntervalIdentifier = null;
  693.  
  694.  
  695.  
  696.  
  697. function processChunk()
  698. {
  699. var view = searchableViews[i];
  700.  
  701. if (++i >= searchableViews.length) {
  702. if (panel._currentSearchChunkIntervalIdentifier === chunkIntervalIdentifier)
  703. delete panel._currentSearchChunkIntervalIdentifier;
  704. clearInterval(chunkIntervalIdentifier);
  705. }
  706.  
  707. if (!view)
  708. return;
  709.  
  710. view.currentQuery = query;
  711. view.performSearch(query, boundFinishedCallback);
  712. }
  713.  
  714. processChunk();
  715.  
  716. chunkIntervalIdentifier = setInterval(processChunk, 25);
  717. this._currentSearchChunkIntervalIdentifier = chunkIntervalIdentifier;
  718. },
  719.  
  720. jumpToNextSearchResult: function()
  721. {
  722. if (!this.showView || !this._searchResults || !this._searchResults.length)
  723. return;
  724.  
  725. var showFirstResult = false;
  726.  
  727. this._currentSearchResultIndex = this._searchResults.indexOf(this.visibleView);
  728. if (this._currentSearchResultIndex === -1) {
  729. this._currentSearchResultIndex = 0;
  730. showFirstResult = true;
  731. }
  732.  
  733. var currentView = this._searchResults[this._currentSearchResultIndex];
  734.  
  735. if (currentView.showingLastSearchResult()) {
  736. if (++this._currentSearchResultIndex >= this._searchResults.length)
  737. this._currentSearchResultIndex = 0;
  738. currentView = this._searchResults[this._currentSearchResultIndex];
  739. showFirstResult = true;
  740. }
  741.  
  742. WebInspector.searchController.updateCurrentMatchIndex(this._currentSearchResultIndex, this);
  743.  
  744. if (currentView !== this.visibleView) {
  745. this.showView(currentView);
  746. WebInspector.searchController.showSearchField();
  747. }
  748.  
  749. if (showFirstResult)
  750. currentView.jumpToFirstSearchResult();
  751. else
  752. currentView.jumpToNextSearchResult();
  753. },
  754.  
  755. jumpToPreviousSearchResult: function()
  756. {
  757. if (!this.showView || !this._searchResults || !this._searchResults.length)
  758. return;
  759.  
  760. var showLastResult = false;
  761.  
  762. this._currentSearchResultIndex = this._searchResults.indexOf(this.visibleView);
  763. if (this._currentSearchResultIndex === -1) {
  764. this._currentSearchResultIndex = 0;
  765. showLastResult = true;
  766. }
  767.  
  768. var currentView = this._searchResults[this._currentSearchResultIndex];
  769.  
  770. if (currentView.showingFirstSearchResult()) {
  771. if (--this._currentSearchResultIndex < 0)
  772. this._currentSearchResultIndex = (this._searchResults.length - 1);
  773. currentView = this._searchResults[this._currentSearchResultIndex];
  774. showLastResult = true;
  775. }
  776.  
  777. WebInspector.searchController.updateCurrentMatchIndex(this._currentSearchResultIndex, this);
  778.  
  779. if (currentView !== this.visibleView) {
  780. this.showView(currentView);
  781. WebInspector.searchController.showSearchField();
  782. }
  783.  
  784. if (showLastResult)
  785. currentView.jumpToLastSearchResult();
  786. else
  787. currentView.jumpToPreviousSearchResult();
  788. },
  789.  
  790. _searchableViews: function()
  791. {
  792. var views = [];
  793.  
  794. const visibleView = this.visibleView;
  795. if (visibleView && visibleView.performSearch)
  796. views.push(visibleView);
  797.  
  798. var profilesLength = this._profiles.length;
  799. for (var i = 0; i < profilesLength; ++i) {
  800. var profile = this._profiles[i];
  801. var view = profile.view();
  802. if (!view.performSearch || view === visibleView)
  803. continue;
  804. views.push(view);
  805. }
  806.  
  807. return views;
  808. },
  809.  
  810. searchMatchFound: function(view, matches)
  811. {
  812. view.profile._profilesTreeElement.searchMatches = matches;
  813. },
  814.  
  815. searchCanceled: function()
  816. {
  817. if (this._searchResults) {
  818. for (var i = 0; i < this._searchResults.length; ++i) {
  819. var view = this._searchResults[i];
  820. if (view.searchCanceled)
  821. view.searchCanceled();
  822. delete view.currentQuery;
  823. }
  824. }
  825.  
  826. WebInspector.Panel.prototype.searchCanceled.call(this);
  827.  
  828. if (this._currentSearchChunkIntervalIdentifier) {
  829. clearInterval(this._currentSearchChunkIntervalIdentifier);
  830. delete this._currentSearchChunkIntervalIdentifier;
  831. }
  832.  
  833. this._totalSearchMatches = 0;
  834. this._currentSearchResultIndex = 0;
  835. this._searchResults = [];
  836.  
  837. if (!this._profiles)
  838. return;
  839.  
  840. for (var i = 0; i < this._profiles.length; ++i) {
  841. var profile = this._profiles[i];
  842. profile._profilesTreeElement.searchMatches = 0;
  843. }
  844. },
  845.  
  846. _updateInterface: function()
  847. {
  848.  
  849. if (this._profilerEnabled) {
  850. this.enableToggleButton.title = WebInspector.UIString("Profiling enabled. Click to disable.");
  851. this.enableToggleButton.toggled = true;
  852. this.recordButton.visible = true;
  853. this.profileViewStatusBarItemsContainer.removeStyleClass("hidden");
  854. this.clearResultsButton.element.removeStyleClass("hidden");
  855. this.panelEnablerView.detach();
  856. } else {
  857. this.enableToggleButton.title = WebInspector.UIString("Profiling disabled. Click to enable.");
  858. this.enableToggleButton.toggled = false;
  859. this.recordButton.visible = false;
  860. this.profileViewStatusBarItemsContainer.addStyleClass("hidden");
  861. this.clearResultsButton.element.addStyleClass("hidden");
  862. this.panelEnablerView.show(this.element);
  863. }
  864. },
  865.  
  866. get profilerEnabled()
  867. {
  868. return this._profilerEnabled;
  869. },
  870.  
  871. enableProfiler: function()
  872. {
  873. if (this._profilerEnabled)
  874. return;
  875. this._toggleProfiling(this.panelEnablerView.alwaysEnabled);
  876. },
  877.  
  878. disableProfiler: function()
  879. {
  880. if (!this._profilerEnabled)
  881. return;
  882. this._toggleProfiling(this.panelEnablerView.alwaysEnabled);
  883. },
  884.  
  885.  
  886. _onToggleProfiling: function(event) {
  887. this._toggleProfiling(true);
  888. },
  889.  
  890.  
  891. _toggleProfiling: function(always)
  892. {
  893. if (this._profilerEnabled) {
  894. WebInspector.settings.profilerEnabled.set(false);
  895. ProfilerAgent.disable(this._profilerWasDisabled.bind(this));
  896. } else {
  897. WebInspector.settings.profilerEnabled.set(always);
  898. ProfilerAgent.enable(this._profilerWasEnabled.bind(this));
  899. }
  900. },
  901.  
  902. _populateProfiles: function()
  903. {
  904. if (!this._profilerEnabled || this._profilesWereRequested)
  905. return;
  906.  
  907.  
  908. function populateCallback(error, profileHeaders) {
  909. if (error)
  910. return;
  911. profileHeaders.sort(function(a, b) { return a.uid - b.uid; });
  912. var profileHeadersLength = profileHeaders.length;
  913. for (var i = 0; i < profileHeadersLength; ++i) {
  914. var profileHeader = profileHeaders[i];
  915. var profileType = this.getProfileType(profileHeader.typeId);
  916. this.addProfileHeader(profileType.createProfile(profileHeader));
  917. }
  918. }
  919.  
  920. ProfilerAgent.getProfileHeaders(populateCallback.bind(this));
  921.  
  922. this._profilesWereRequested = true;
  923. },
  924.  
  925.  
  926. sidebarResized: function(event)
  927. {
  928. this.onResize();
  929. },
  930.  
  931. onResize: function()
  932. {
  933. var minFloatingStatusBarItemsOffset = document.getElementById("panel-status-bar").totalOffsetLeft() + this._statusBarButtons.length * WebInspector.StatusBarButton.width;
  934. this.profileViewStatusBarItemsContainer.style.left = Math.max(minFloatingStatusBarItemsOffset, this.splitView.sidebarWidth()) + "px";
  935. },
  936.  
  937.  
  938. setRecordingProfile: function(profileType, isProfiling)
  939. {
  940. var profileTypeObject = this.getProfileType(profileType);
  941. profileTypeObject.setRecordingProfile(isProfiling);
  942. var temporaryProfile = this.findTemporaryProfile(profileType);
  943. if (!!temporaryProfile === isProfiling)
  944. return;
  945. if (!temporaryProfile)
  946. temporaryProfile = profileTypeObject.createTemporaryProfile();
  947. if (isProfiling)
  948. this.addProfileHeader(temporaryProfile);
  949. else
  950. this._removeTemporaryProfile(profileType);
  951. this.recordButton.toggled = isProfiling;
  952. this.recordButton.title = profileTypeObject.buttonTooltip;
  953. if (isProfiling)
  954. this._launcherView.profileStarted();
  955. else
  956. this._launcherView.profileFinished();
  957. },
  958.  
  959. takeHeapSnapshot: function()
  960. {
  961. var temporaryRecordingProfile = this.findTemporaryProfile(WebInspector.HeapSnapshotProfileType.TypeId);
  962. if (!temporaryRecordingProfile) {
  963. var profileTypeObject = this.getProfileType(WebInspector.HeapSnapshotProfileType.TypeId);
  964. this.addProfileHeader(profileTypeObject.createTemporaryProfile());
  965. }
  966. this._launcherView.profileStarted();
  967. function done() {
  968. this._launcherView.profileFinished();
  969. }
  970. ProfilerAgent.takeHeapSnapshot(done.bind(this));
  971. WebInspector.userMetrics.ProfilesHeapProfileTaken.record();
  972. },
  973.  
  974.  
  975. _reportHeapSnapshotProgress: function(done, total)
  976. {
  977. var temporaryProfile = this.findTemporaryProfile(WebInspector.HeapSnapshotProfileType.TypeId);
  978. if (temporaryProfile) {
  979. temporaryProfile.sidebarElement.subtitle = WebInspector.UIString("%.2f%", (done / total) * 100);
  980. temporaryProfile.sidebarElement.wait = true;
  981. if (done >= total)
  982. this._removeTemporaryProfile(WebInspector.HeapSnapshotProfileType.TypeId);
  983. }
  984. },
  985.  
  986.  
  987. appendApplicableItems: function(event, contextMenu, target)
  988. {
  989. if (WebInspector.inspectorView.currentPanel() !== this)
  990. return;
  991.  
  992. var object =   (target);
  993. var objectId = object.objectId;
  994. if (!objectId)
  995. return;
  996.  
  997. var heapProfiles = this.getProfiles(WebInspector.HeapSnapshotProfileType.TypeId);
  998. if (!heapProfiles.length)
  999. return;
  1000.  
  1001. function revealInView(viewName)
  1002. {
  1003. ProfilerAgent.getHeapObjectId(objectId, didReceiveHeapObjectId.bind(this, viewName));
  1004. }
  1005.  
  1006. function didReceiveHeapObjectId(viewName, error, result)
  1007. {
  1008. if (WebInspector.inspectorView.currentPanel() !== this)
  1009. return;
  1010. if (!error)
  1011. this.showObject(result, viewName);
  1012. }
  1013.  
  1014. contextMenu.appendItem(WebInspector.UIString("Reveal in Dominators View"), revealInView.bind(this, "Dominators"));
  1015. contextMenu.appendItem(WebInspector.UIString("Reveal in Summary View"), revealInView.bind(this, "Summary"));
  1016. },
  1017.  
  1018. __proto__: WebInspector.Panel.prototype
  1019. }
  1020.  
  1021.  
  1022. WebInspector.ProfilerDispatcher = function(profilesPanel)
  1023. {
  1024. this._profilesPanel = profilesPanel;
  1025. }
  1026.  
  1027. WebInspector.ProfilerDispatcher.prototype = {
  1028.  
  1029. addProfileHeader: function(profile)
  1030. {
  1031. var profileType = this._profilesPanel.getProfileType(profile.typeId);
  1032. this._profilesPanel.addProfileHeader(profileType.createProfile(profile));
  1033. },
  1034.  
  1035.  
  1036. addHeapSnapshotChunk: function(uid, chunk)
  1037. {
  1038. this._profilesPanel._addHeapSnapshotChunk(uid, chunk);
  1039. },
  1040.  
  1041.  
  1042. finishHeapSnapshot: function(uid)
  1043. {
  1044. this._profilesPanel._finishHeapSnapshot(uid);
  1045. },
  1046.  
  1047.  
  1048. setRecordingProfile: function(isProfiling)
  1049. {
  1050. this._profilesPanel.setRecordingProfile(WebInspector.CPUProfileType.TypeId, isProfiling);
  1051. },
  1052.  
  1053.  
  1054. resetProfiles: function()
  1055. {
  1056. this._profilesPanel._reset();
  1057. },
  1058.  
  1059.  
  1060. reportHeapSnapshotProgress: function(done, total)
  1061. {
  1062. this._profilesPanel._reportHeapSnapshotProgress(done, total);
  1063. }
  1064. }
  1065.  
  1066.  
  1067. WebInspector.ProfileSidebarTreeElement = function(profile, titleFormat, className)
  1068. {
  1069. this.profile = profile;
  1070. this._titleFormat = titleFormat;
  1071.  
  1072. if (this.profile.title.startsWith(UserInitiatedProfileName))
  1073. this._profileNumber = this.profile.title.substring(UserInitiatedProfileName.length + 1);
  1074.  
  1075. WebInspector.SidebarTreeElement.call(this, className, "", "", profile, false);
  1076.  
  1077. this.refreshTitles();
  1078. }
  1079.  
  1080. WebInspector.ProfileSidebarTreeElement.prototype = {
  1081. onselect: function()
  1082. {
  1083. if (!this._suppressOnSelect)
  1084. this.treeOutline.panel.showProfile(this.profile);
  1085. },
  1086.  
  1087. ondelete: function()
  1088. {
  1089. this.treeOutline.panel._removeProfileHeader(this.profile);
  1090. return true;
  1091. },
  1092.  
  1093. get mainTitle()
  1094. {
  1095. if (this._mainTitle)
  1096. return this._mainTitle;
  1097. if (this.profile.title.startsWith(UserInitiatedProfileName))
  1098. return WebInspector.UIString(this._titleFormat, this._profileNumber);
  1099. return this.profile.title;
  1100. },
  1101.  
  1102. set mainTitle(x)
  1103. {
  1104. this._mainTitle = x;
  1105. this.refreshTitles();
  1106. },
  1107.  
  1108. set searchMatches(matches)
  1109. {
  1110. if (!matches) {
  1111. if (!this.bubbleElement)
  1112. return;
  1113. this.bubbleElement.removeStyleClass("search-matches");
  1114. this.bubbleText = "";
  1115. return;
  1116. }
  1117.  
  1118. this.bubbleText = matches;
  1119. this.bubbleElement.addStyleClass("search-matches");
  1120. },
  1121.  
  1122.  
  1123. handleContextMenuEvent: function(event)
  1124. {
  1125. var profile = this.profile;
  1126. var contextMenu = new WebInspector.ContextMenu(event);
  1127. var profilesPanel = WebInspector.ProfilesPanel._instance;
  1128.  
  1129. if (profile.canSaveToFile()) {
  1130. contextMenu.appendItem(WebInspector.UIString("Save Heap Snapshot\u2026"), profile.saveToFile.bind(profile));
  1131. contextMenu.appendItem(WebInspector.UIString("Load Heap Snapshot\u2026"), profilesPanel._fileSelectorElement.click.bind(profilesPanel._fileSelectorElement));
  1132. contextMenu.appendItem(WebInspector.UIString("Delete Heap Snapshot"), this.ondelete.bind(this));
  1133. } else {
  1134. contextMenu.appendItem(WebInspector.UIString("Load Heap Snapshot\u2026"), profilesPanel._fileSelectorElement.click.bind(profilesPanel._fileSelectorElement));
  1135. contextMenu.appendItem(WebInspector.UIString("Delete profile"), this.ondelete.bind(this));
  1136. }
  1137. contextMenu.show();
  1138. },
  1139.  
  1140. __proto__: WebInspector.SidebarTreeElement.prototype
  1141. }
  1142.  
  1143.  
  1144. WebInspector.ProfileGroupSidebarTreeElement = function(title, subtitle)
  1145. {
  1146. WebInspector.SidebarTreeElement.call(this, "profile-group-sidebar-tree-item", title, subtitle, null, true);
  1147. }
  1148.  
  1149. WebInspector.ProfileGroupSidebarTreeElement.prototype = {
  1150. onselect: function()
  1151. {
  1152. if (this.children.length > 0)
  1153. WebInspector.ProfilesPanel._instance.showProfile(this.children[this.children.length - 1].profile);
  1154. },
  1155.  
  1156. __proto__: WebInspector.SidebarTreeElement.prototype
  1157. }
  1158.  
  1159.  
  1160. WebInspector.ProfilesSidebarTreeElement = function(panel)
  1161. {
  1162. this._panel = panel;
  1163. this.small = false;
  1164.  
  1165. WebInspector.SidebarTreeElement.call(this, "profile-launcher-view-tree-item", WebInspector.UIString("Profiles"), "", null, false);
  1166. }
  1167.  
  1168. WebInspector.ProfilesSidebarTreeElement.prototype = {
  1169. onselect: function()
  1170. {
  1171. this._panel._showLauncherView();
  1172. },
  1173.  
  1174. get selectable()
  1175. {
  1176. return true;
  1177. },
  1178.  
  1179. __proto__: WebInspector.SidebarTreeElement.prototype
  1180. }
  1181.  
  1182.  
  1183.  
  1184.  
  1185. WebInspector.ProfileDataGridNode = function(profileView, profileNode, owningTree, hasChildren)
  1186. {
  1187. this.profileView = profileView;
  1188. this.profileNode = profileNode;
  1189.  
  1190. WebInspector.DataGridNode.call(this, null, hasChildren);
  1191.  
  1192. this.addEventListener("populate", this._populate, this);
  1193.  
  1194. this.tree = owningTree;
  1195.  
  1196. this.childrenByCallUID = {};
  1197. this.lastComparator = null;
  1198.  
  1199. this.callUID = profileNode.callUID;
  1200. this.selfTime = profileNode.selfTime;
  1201. this.totalTime = profileNode.totalTime;
  1202. this.functionName = profileNode.functionName;
  1203. this.numberOfCalls = profileNode.numberOfCalls;
  1204. this.url = profileNode.url;
  1205. }
  1206.  
  1207. WebInspector.ProfileDataGridNode.prototype = {
  1208. get data()
  1209. {
  1210. function formatMilliseconds(time)
  1211. {
  1212. return Number.secondsToString(time / 1000, !Capabilities.samplingCPUProfiler);
  1213. }
  1214.  
  1215. var data = {};
  1216.  
  1217. data["function"] = this.functionName;
  1218. data["calls"] = this.numberOfCalls;
  1219.  
  1220. if (this.profileView.showSelfTimeAsPercent.get())
  1221. data["self"] = WebInspector.UIString("%.2f%", this.selfPercent);
  1222. else
  1223. data["self"] = formatMilliseconds(this.selfTime);
  1224.  
  1225. if (this.profileView.showTotalTimeAsPercent.get())
  1226. data["total"] = WebInspector.UIString("%.2f%", this.totalPercent);
  1227. else
  1228. data["total"] = formatMilliseconds(this.totalTime);
  1229.  
  1230. if (this.profileView.showAverageTimeAsPercent.get())
  1231. data["average"] = WebInspector.UIString("%.2f%", this.averagePercent);
  1232. else
  1233. data["average"] = formatMilliseconds(this.averageTime);
  1234.  
  1235. return data;
  1236. },
  1237.  
  1238. createCell: function(columnIdentifier)
  1239. {
  1240. var cell = WebInspector.DataGridNode.prototype.createCell.call(this, columnIdentifier);
  1241.  
  1242. if (columnIdentifier === "self" && this._searchMatchedSelfColumn)
  1243. cell.addStyleClass("highlight");
  1244. else if (columnIdentifier === "total" && this._searchMatchedTotalColumn)
  1245. cell.addStyleClass("highlight");
  1246. else if (columnIdentifier === "average" && this._searchMatchedAverageColumn)
  1247. cell.addStyleClass("highlight");
  1248. else if (columnIdentifier === "calls" && this._searchMatchedCallsColumn)
  1249. cell.addStyleClass("highlight");
  1250.  
  1251. if (columnIdentifier !== "function")
  1252. return cell;
  1253.  
  1254. if (this.profileNode._searchMatchedFunctionColumn)
  1255. cell.addStyleClass("highlight");
  1256.  
  1257. if (this.profileNode.url) {
  1258.  
  1259. var lineNumber = this.profileNode.lineNumber ? this.profileNode.lineNumber - 1 : 0;
  1260. var urlElement = this.profileView._linkifier.linkifyLocation(this.profileNode.url, lineNumber, 0, "profile-node-file");
  1261. urlElement.style.maxWidth = "75%";
  1262. cell.insertBefore(urlElement, cell.firstChild);
  1263. }
  1264.  
  1265. return cell;
  1266. },
  1267.  
  1268. select: function(supressSelectedEvent)
  1269. {
  1270. WebInspector.DataGridNode.prototype.select.call(this, supressSelectedEvent);
  1271. this.profileView._dataGridNodeSelected(this);
  1272. },
  1273.  
  1274. deselect: function(supressDeselectedEvent)
  1275. {
  1276. WebInspector.DataGridNode.prototype.deselect.call(this, supressDeselectedEvent);
  1277. this.profileView._dataGridNodeDeselected(this);
  1278. },
  1279.  
  1280. sort: function(  comparator,   force)
  1281. {
  1282. var gridNodeGroups = [[this]];
  1283.  
  1284. for (var gridNodeGroupIndex = 0; gridNodeGroupIndex < gridNodeGroups.length; ++gridNodeGroupIndex) {
  1285. var gridNodes = gridNodeGroups[gridNodeGroupIndex];
  1286. var count = gridNodes.length;
  1287.  
  1288. for (var index = 0; index < count; ++index) {
  1289. var gridNode = gridNodes[index];
  1290.  
  1291.  
  1292.  
  1293. if (!force && (!gridNode.expanded || gridNode.lastComparator === comparator)) {
  1294. if (gridNode.children.length)
  1295. gridNode.shouldRefreshChildren = true;
  1296. continue;
  1297. }
  1298.  
  1299. gridNode.lastComparator = comparator;
  1300.  
  1301. var children = gridNode.children;
  1302. var childCount = children.length;
  1303.  
  1304. if (childCount) {
  1305. children.sort(comparator);
  1306.  
  1307. for (var childIndex = 0; childIndex < childCount; ++childIndex)
  1308. children[childIndex]._recalculateSiblings(childIndex);
  1309.  
  1310. gridNodeGroups.push(children);
  1311. }
  1312. }
  1313. }
  1314. },
  1315.  
  1316. insertChild: function(  profileDataGridNode, index)
  1317. {
  1318. WebInspector.DataGridNode.prototype.insertChild.call(this, profileDataGridNode, index);
  1319.  
  1320. this.childrenByCallUID[profileDataGridNode.callUID] = profileDataGridNode;
  1321. },
  1322.  
  1323. removeChild: function(  profileDataGridNode)
  1324. {
  1325. WebInspector.DataGridNode.prototype.removeChild.call(this, profileDataGridNode);
  1326.  
  1327. delete this.childrenByCallUID[profileDataGridNode.callUID];
  1328. },
  1329.  
  1330. removeChildren: function(  profileDataGridNode)
  1331. {
  1332. WebInspector.DataGridNode.prototype.removeChildren.call(this);
  1333.  
  1334. this.childrenByCallUID = {};
  1335. },
  1336.  
  1337. findChild: function(  node)
  1338. {
  1339. if (!node)
  1340. return null;
  1341. return this.childrenByCallUID[node.callUID];
  1342. },
  1343.  
  1344. get averageTime()
  1345. {
  1346. return this.selfTime / Math.max(1, this.numberOfCalls);
  1347. },
  1348.  
  1349. get averagePercent()
  1350. {
  1351. return this.averageTime / this.tree.totalTime * 100.0;
  1352. },
  1353.  
  1354. get selfPercent()
  1355. {
  1356. return this.selfTime / this.tree.totalTime * 100.0;
  1357. },
  1358.  
  1359. get totalPercent()
  1360. {
  1361. return this.totalTime / this.tree.totalTime * 100.0;
  1362. },
  1363.  
  1364. get _parent()
  1365. {
  1366. return this.parent !== this.dataGrid ? this.parent : this.tree;
  1367. },
  1368.  
  1369. _populate: function()
  1370. {
  1371. this._sharedPopulate();
  1372.  
  1373. if (this._parent) {
  1374. var currentComparator = this._parent.lastComparator;
  1375.  
  1376. if (currentComparator)
  1377. this.sort(currentComparator, true);
  1378. }
  1379.  
  1380. if (this.removeEventListener)
  1381. this.removeEventListener("populate", this._populate, this);
  1382. },
  1383.  
  1384.  
  1385.  
  1386. _save: function()
  1387. {
  1388. if (this._savedChildren)
  1389. return;
  1390.  
  1391. this._savedSelfTime = this.selfTime;
  1392. this._savedTotalTime = this.totalTime;
  1393. this._savedNumberOfCalls = this.numberOfCalls;
  1394.  
  1395. this._savedChildren = this.children.slice();
  1396. },
  1397.  
  1398.  
  1399.  
  1400. _restore: function()
  1401. {
  1402. if (!this._savedChildren)
  1403. return;
  1404.  
  1405. this.selfTime = this._savedSelfTime;
  1406. this.totalTime = this._savedTotalTime;
  1407. this.numberOfCalls = this._savedNumberOfCalls;
  1408.  
  1409. this.removeChildren();
  1410.  
  1411. var children = this._savedChildren;
  1412. var count = children.length;
  1413.  
  1414. for (var index = 0; index < count; ++index) {
  1415. children[index]._restore();
  1416. this.appendChild(children[index]);
  1417. }
  1418. },
  1419.  
  1420. _merge: function(child, shouldAbsorb)
  1421. {
  1422. this.selfTime += child.selfTime;
  1423.  
  1424. if (!shouldAbsorb) {
  1425. this.totalTime += child.totalTime;
  1426. this.numberOfCalls += child.numberOfCalls;
  1427. }
  1428.  
  1429. var children = this.children.slice();
  1430.  
  1431. this.removeChildren();
  1432.  
  1433. var count = children.length;
  1434.  
  1435. for (var index = 0; index < count; ++index) {
  1436. if (!shouldAbsorb || children[index] !== child)
  1437. this.appendChild(children[index]);
  1438. }
  1439.  
  1440. children = child.children.slice();
  1441. count = children.length;
  1442.  
  1443. for (var index = 0; index < count; ++index) {
  1444. var orphanedChild = children[index],
  1445. existingChild = this.childrenByCallUID[orphanedChild.callUID];
  1446.  
  1447. if (existingChild)
  1448. existingChild._merge(orphanedChild, false);
  1449. else
  1450. this.appendChild(orphanedChild);
  1451. }
  1452. },
  1453.  
  1454. __proto__: WebInspector.DataGridNode.prototype
  1455. }
  1456.  
  1457.  
  1458. WebInspector.ProfileDataGridTree = function(profileView, profileNode)
  1459. {
  1460. this.tree = this;
  1461. this.children = [];
  1462.  
  1463. this.profileView = profileView;
  1464.  
  1465. this.totalTime = profileNode.totalTime;
  1466. this.lastComparator = null;
  1467.  
  1468. this.childrenByCallUID = {};
  1469. }
  1470.  
  1471. WebInspector.ProfileDataGridTree.prototype = {
  1472. get expanded()
  1473. {
  1474. return true;
  1475. },
  1476.  
  1477. appendChild: function(child)
  1478. {
  1479. this.insertChild(child, this.children.length);
  1480. },
  1481.  
  1482. insertChild: function(child, index)
  1483. {
  1484. this.children.splice(index, 0, child);
  1485. this.childrenByCallUID[child.callUID] = child;
  1486. },
  1487.  
  1488. removeChildren: function()
  1489. {
  1490. this.children = [];
  1491. this.childrenByCallUID = {};
  1492. },
  1493.  
  1494. findChild: WebInspector.ProfileDataGridNode.prototype.findChild,
  1495. sort: WebInspector.ProfileDataGridNode.prototype.sort,
  1496.  
  1497. _save: function()
  1498. {
  1499. if (this._savedChildren)
  1500. return;
  1501.  
  1502. this._savedTotalTime = this.totalTime;
  1503. this._savedChildren = this.children.slice();
  1504. },
  1505.  
  1506. restore: function()
  1507. {
  1508. if (!this._savedChildren)
  1509. return;
  1510.  
  1511. this.children = this._savedChildren;
  1512. this.totalTime = this._savedTotalTime;
  1513.  
  1514. var children = this.children;
  1515. var count = children.length;
  1516.  
  1517. for (var index = 0; index < count; ++index)
  1518. children[index]._restore();
  1519.  
  1520. this._savedChildren = null;
  1521. }
  1522. }
  1523.  
  1524. WebInspector.ProfileDataGridTree.propertyComparators = [{}, {}];
  1525.  
  1526. WebInspector.ProfileDataGridTree.propertyComparator = function(  property,   isAscending)
  1527. {
  1528. var comparator = WebInspector.ProfileDataGridTree.propertyComparators[(isAscending ? 1 : 0)][property];
  1529.  
  1530. if (!comparator) {
  1531. if (isAscending) {
  1532. comparator = function(lhs, rhs)
  1533. {
  1534. if (lhs[property] < rhs[property])
  1535. return -1;
  1536.  
  1537. if (lhs[property] > rhs[property])
  1538. return 1;
  1539.  
  1540. return 0;
  1541. }
  1542. } else {
  1543. comparator = function(lhs, rhs)
  1544. {
  1545. if (lhs[property] > rhs[property])
  1546. return -1;
  1547.  
  1548. if (lhs[property] < rhs[property])
  1549. return 1;
  1550.  
  1551. return 0;
  1552. }
  1553. }
  1554.  
  1555. WebInspector.ProfileDataGridTree.propertyComparators[(isAscending ? 1 : 0)][property] = comparator;
  1556. }
  1557.  
  1558. return comparator;
  1559. }
  1560. ;
  1561.  
  1562.  
  1563.  
  1564.  
  1565.  
  1566.  
  1567.  
  1568.  
  1569.  
  1570. WebInspector.BottomUpProfileDataGridNode = function(  profileView,   profileNode,   owningTree)
  1571. {
  1572. WebInspector.ProfileDataGridNode.call(this, profileView, profileNode, owningTree, this._willHaveChildren(profileNode));
  1573.  
  1574. this._remainingNodeInfos = [];
  1575. }
  1576.  
  1577. WebInspector.BottomUpProfileDataGridNode.prototype = {
  1578. _takePropertiesFromProfileDataGridNode: function(  profileDataGridNode)
  1579. {
  1580. this._save();
  1581.  
  1582. this.selfTime = profileDataGridNode.selfTime;
  1583. this.totalTime = profileDataGridNode.totalTime;
  1584. this.numberOfCalls = profileDataGridNode.numberOfCalls;
  1585. },
  1586.  
  1587.  
  1588. _keepOnlyChild: function(  child)
  1589. {
  1590. this._save();
  1591.  
  1592. this.removeChildren();
  1593. this.appendChild(child);
  1594. },
  1595.  
  1596. _exclude: function(aCallUID)
  1597. {
  1598. if (this._remainingNodeInfos)
  1599. this._populate();
  1600.  
  1601. this._save();
  1602.  
  1603. var children = this.children;
  1604. var index = this.children.length;
  1605.  
  1606. while (index--)
  1607. children[index]._exclude(aCallUID);
  1608.  
  1609. var child = this.childrenByCallUID[aCallUID];
  1610.  
  1611. if (child)
  1612. this._merge(child, true);
  1613. },
  1614.  
  1615. _restore: function()
  1616. {
  1617. WebInspector.ProfileDataGridNode.prototype._restore();
  1618.  
  1619. if (!this.children.length)
  1620. this.hasChildren = this._willHaveChildren(this.profileNode);
  1621. },
  1622.  
  1623. _merge: function(  child,   shouldAbsorb)
  1624. {
  1625. this.selfTime -= child.selfTime;
  1626.  
  1627. WebInspector.ProfileDataGridNode.prototype._merge.call(this, child, shouldAbsorb);
  1628. },
  1629.  
  1630. _sharedPopulate: function()
  1631. {
  1632. var remainingNodeInfos = this._remainingNodeInfos;
  1633. var count = remainingNodeInfos.length;
  1634.  
  1635. for (var index = 0; index < count; ++index) {
  1636. var nodeInfo = remainingNodeInfos[index];
  1637. var ancestor = nodeInfo.ancestor;
  1638. var focusNode = nodeInfo.focusNode;
  1639. var child = this.findChild(ancestor);
  1640.  
  1641.  
  1642. if (child) {
  1643. var totalTimeAccountedFor = nodeInfo.totalTimeAccountedFor;
  1644.  
  1645. child.selfTime += focusNode.selfTime;
  1646. child.numberOfCalls += focusNode.numberOfCalls;
  1647.  
  1648. if (!totalTimeAccountedFor)
  1649. child.totalTime += focusNode.totalTime;
  1650. } else {
  1651.  
  1652.  
  1653. child = new WebInspector.BottomUpProfileDataGridNode(this.profileView, ancestor, this.tree);
  1654.  
  1655. if (ancestor !== focusNode) {
  1656.  
  1657. child.selfTime = focusNode.selfTime;
  1658. child.totalTime = focusNode.totalTime;
  1659. child.numberOfCalls = focusNode.numberOfCalls;
  1660. }
  1661.  
  1662. this.appendChild(child);
  1663. }
  1664.  
  1665. var parent = ancestor.parent;
  1666. if (parent && parent.parent) {
  1667. nodeInfo.ancestor = parent;
  1668. child._remainingNodeInfos.push(nodeInfo);
  1669. }
  1670. }
  1671.  
  1672. delete this._remainingNodeInfos;
  1673. },
  1674.  
  1675. _willHaveChildren: function(profileNode)
  1676. {
  1677.  
  1678.  
  1679. return !!(profileNode.parent && profileNode.parent.parent);
  1680. },
  1681.  
  1682. __proto__: WebInspector.ProfileDataGridNode.prototype
  1683. }
  1684.  
  1685.  
  1686. WebInspector.BottomUpProfileDataGridTree = function(  aProfileView,   aProfileNode)
  1687. {
  1688. WebInspector.ProfileDataGridTree.call(this, aProfileView, aProfileNode);
  1689.  
  1690.  
  1691. var profileNodeUIDs = 0;
  1692. var profileNodeGroups = [[], [aProfileNode]];
  1693. var visitedProfileNodesForCallUID = {};
  1694.  
  1695. this._remainingNodeInfos = [];
  1696.  
  1697. for (var profileNodeGroupIndex = 0; profileNodeGroupIndex < profileNodeGroups.length; ++profileNodeGroupIndex) {
  1698. var parentProfileNodes = profileNodeGroups[profileNodeGroupIndex];
  1699. var profileNodes = profileNodeGroups[++profileNodeGroupIndex];
  1700. var count = profileNodes.length;
  1701.  
  1702. for (var index = 0; index < count; ++index) {
  1703. var profileNode = profileNodes[index];
  1704.  
  1705. if (!profileNode.UID)
  1706. profileNode.UID = ++profileNodeUIDs;
  1707.  
  1708. if (profileNode.head && profileNode !== profileNode.head) {
  1709.  
  1710. var visitedNodes = visitedProfileNodesForCallUID[profileNode.callUID];
  1711. var totalTimeAccountedFor = false;
  1712.  
  1713. if (!visitedNodes) {
  1714. visitedNodes = {}
  1715. visitedProfileNodesForCallUID[profileNode.callUID] = visitedNodes;
  1716. } else {
  1717.  
  1718.  
  1719. var parentCount = parentProfileNodes.length;
  1720. for (var parentIndex = 0; parentIndex < parentCount; ++parentIndex) {
  1721. if (visitedNodes[parentProfileNodes[parentIndex].UID]) {
  1722. totalTimeAccountedFor = true;
  1723. break;
  1724. }
  1725. }
  1726. }
  1727.  
  1728. visitedNodes[profileNode.UID] = true;
  1729.  
  1730. this._remainingNodeInfos.push({ ancestor:profileNode, focusNode:profileNode, totalTimeAccountedFor:totalTimeAccountedFor });
  1731. }
  1732.  
  1733. var children = profileNode.children;
  1734. if (children.length) {
  1735. profileNodeGroups.push(parentProfileNodes.concat([profileNode]))
  1736. profileNodeGroups.push(children);
  1737. }
  1738. }
  1739. }
  1740.  
  1741.  
  1742. var any =  this;
  1743. var node =  any;
  1744. WebInspector.BottomUpProfileDataGridNode.prototype._populate.call(node);
  1745.  
  1746. return this;
  1747. }
  1748.  
  1749. WebInspector.BottomUpProfileDataGridTree.prototype = {
  1750.  
  1751. focus: function(  profileDataGridNode)
  1752. {
  1753. if (!profileDataGridNode)
  1754. return;
  1755.  
  1756. this._save();
  1757.  
  1758. var currentNode = profileDataGridNode;
  1759. var focusNode = profileDataGridNode;
  1760.  
  1761. while (currentNode.parent && (currentNode instanceof WebInspector.ProfileDataGridNode)) {
  1762. currentNode._takePropertiesFromProfileDataGridNode(profileDataGridNode);
  1763.  
  1764. focusNode = currentNode;
  1765. currentNode = currentNode.parent;
  1766.  
  1767. if (currentNode instanceof WebInspector.ProfileDataGridNode)
  1768. currentNode._keepOnlyChild(focusNode);
  1769. }
  1770.  
  1771. this.children = [focusNode];
  1772. this.totalTime = profileDataGridNode.totalTime;
  1773. },
  1774.  
  1775. exclude: function(  profileDataGridNode)
  1776. {
  1777. if (!profileDataGridNode)
  1778. return;
  1779.  
  1780. this._save();
  1781.  
  1782. var excludedCallUID = profileDataGridNode.callUID;
  1783. var excludedTopLevelChild = this.childrenByCallUID[excludedCallUID];
  1784.  
  1785.  
  1786.  
  1787. if (excludedTopLevelChild)
  1788. this.children.remove(excludedTopLevelChild);
  1789.  
  1790. var children = this.children;
  1791. var count = children.length;
  1792.  
  1793. for (var index = 0; index < count; ++index)
  1794. children[index]._exclude(excludedCallUID);
  1795.  
  1796. if (this.lastComparator)
  1797. this.sort(this.lastComparator, true);
  1798. },
  1799.  
  1800. _sharedPopulate: WebInspector.BottomUpProfileDataGridNode.prototype._sharedPopulate,
  1801.  
  1802. __proto__: WebInspector.ProfileDataGridTree.prototype
  1803. }
  1804. ;
  1805.  
  1806.  
  1807.  
  1808. WebInspector.CPUProfileView = function(profile)
  1809. {
  1810. WebInspector.View.call(this);
  1811.  
  1812. this.element.addStyleClass("profile-view");
  1813.  
  1814. this.showSelfTimeAsPercent = WebInspector.settings.createSetting("cpuProfilerShowSelfTimeAsPercent", true);
  1815. this.showTotalTimeAsPercent = WebInspector.settings.createSetting("cpuProfilerShowTotalTimeAsPercent", true);
  1816. this.showAverageTimeAsPercent = WebInspector.settings.createSetting("cpuProfilerShowAverageTimeAsPercent", true);
  1817. this._viewType = WebInspector.settings.createSetting("cpuProfilerView", WebInspector.CPUProfileView._TypeHeavy);
  1818.  
  1819. var columns = { "self": { title: WebInspector.UIString("Self"), width: "72px", sort: "descending", sortable: true },
  1820. "total": { title: WebInspector.UIString("Total"), width: "72px", sortable: true },
  1821. "average": { title: WebInspector.UIString("Average"), width: "72px", sortable: true },
  1822. "calls": { title: WebInspector.UIString("Calls"), width: "54px", sortable: true },
  1823. "function": { title: WebInspector.UIString("Function"), disclosure: true, sortable: true } };
  1824.  
  1825. if (Capabilities.samplingCPUProfiler) {
  1826. delete columns.average;
  1827. delete columns.calls;
  1828. }
  1829.  
  1830. this.dataGrid = new WebInspector.DataGrid(columns);
  1831. this.dataGrid.addEventListener("sorting changed", this._sortProfile, this);
  1832. this.dataGrid.element.addEventListener("mousedown", this._mouseDownInDataGrid.bind(this), true);
  1833. this.dataGrid.show(this.element);
  1834.  
  1835. this.viewSelectComboBox = new WebInspector.StatusBarComboBox(this._changeView.bind(this));
  1836.  
  1837. var heavyViewOption = document.createElement("option");
  1838. heavyViewOption.label = WebInspector.UIString("Heavy (Bottom Up)");
  1839. heavyViewOption.value = WebInspector.CPUProfileView._TypeHeavy;
  1840. var treeViewOption = document.createElement("option");
  1841. treeViewOption.label = WebInspector.UIString("Tree (Top Down)");
  1842. treeViewOption.value = WebInspector.CPUProfileView._TypeTree;
  1843.  
  1844. this.viewSelectComboBox.addOption(heavyViewOption);
  1845. this.viewSelectComboBox.addOption(treeViewOption);
  1846. this.viewSelectComboBox.select(this._viewType.get() === WebInspector.CPUProfileView._TypeHeavy ? heavyViewOption : treeViewOption);
  1847.  
  1848. this.percentButton = new WebInspector.StatusBarButton("", "percent-time-status-bar-item");
  1849. this.percentButton.addEventListener("click", this._percentClicked, this);
  1850.  
  1851. this.focusButton = new WebInspector.StatusBarButton(WebInspector.UIString("Focus selected function."), "focus-profile-node-status-bar-item");
  1852. this.focusButton.setEnabled(false);
  1853. this.focusButton.addEventListener("click", this._focusClicked, this);
  1854.  
  1855. this.excludeButton = new WebInspector.StatusBarButton(WebInspector.UIString("Exclude selected function."), "exclude-profile-node-status-bar-item");
  1856. this.excludeButton.setEnabled(false);
  1857. this.excludeButton.addEventListener("click", this._excludeClicked, this);
  1858.  
  1859. this.resetButton = new WebInspector.StatusBarButton(WebInspector.UIString("Restore all functions."), "reset-profile-status-bar-item");
  1860. this.resetButton.visible = false;
  1861. this.resetButton.addEventListener("click", this._resetClicked, this);
  1862.  
  1863. this.profile = profile;
  1864.  
  1865. function profileCallback(error, profile)
  1866. {
  1867. if (error)
  1868. return;
  1869.  
  1870. if (!profile.head) {
  1871.  
  1872. return;
  1873. }
  1874. this.profile.head = profile.head;
  1875. this._assignParentsInProfile();
  1876. this._changeView();
  1877. this._updatePercentButton();
  1878. }
  1879.  
  1880. this._linkifier = new WebInspector.Linkifier(new WebInspector.Linkifier.DefaultFormatter(30));
  1881.  
  1882. ProfilerAgent.getProfile(this.profile.profileType().id, this.profile.uid, profileCallback.bind(this));
  1883. }
  1884.  
  1885. WebInspector.CPUProfileView._TypeTree = "Tree";
  1886. WebInspector.CPUProfileView._TypeHeavy = "Heavy";
  1887.  
  1888. WebInspector.CPUProfileView.prototype = {
  1889. get statusBarItems()
  1890. {
  1891. return [this.viewSelectComboBox.element, this.percentButton.element, this.focusButton.element, this.excludeButton.element, this.resetButton.element];
  1892. },
  1893.  
  1894. get bottomUpProfileDataGridTree()
  1895. {
  1896. if (!this._bottomUpProfileDataGridTree) {
  1897. if (this.profile.bottomUpHead)
  1898. this._bottomUpProfileDataGridTree = new WebInspector.TopDownProfileDataGridTree(this, this.profile.bottomUpHead);
  1899. else
  1900. this._bottomUpProfileDataGridTree = new WebInspector.BottomUpProfileDataGridTree(this, this.profile.head);
  1901. }
  1902. return this._bottomUpProfileDataGridTree;
  1903. },
  1904.  
  1905. get topDownProfileDataGridTree()
  1906. {
  1907. if (!this._topDownProfileDataGridTree)
  1908. this._topDownProfileDataGridTree = new WebInspector.TopDownProfileDataGridTree(this, this.profile.head);
  1909. return this._topDownProfileDataGridTree;
  1910. },
  1911.  
  1912. get currentTree()
  1913. {
  1914. return this._currentTree;
  1915. },
  1916.  
  1917. set currentTree(tree)
  1918. {
  1919. this._currentTree = tree;
  1920. this.refresh();
  1921. },
  1922.  
  1923. willHide: function()
  1924. {
  1925. this._currentSearchResultIndex = -1;
  1926. },
  1927.  
  1928. refresh: function()
  1929. {
  1930. var selectedProfileNode = this.dataGrid.selectedNode ? this.dataGrid.selectedNode.profileNode : null;
  1931.  
  1932. this.dataGrid.rootNode().removeChildren();
  1933.  
  1934. var children = this.profileDataGridTree.children;
  1935. var count = children.length;
  1936.  
  1937. for (var index = 0; index < count; ++index)
  1938. this.dataGrid.rootNode().appendChild(children[index]);
  1939.  
  1940. if (selectedProfileNode)
  1941. selectedProfileNode.selected = true;
  1942. },
  1943.  
  1944. refreshVisibleData: function()
  1945. {
  1946. var child = this.dataGrid.rootNode().children[0];
  1947. while (child) {
  1948. child.refresh();
  1949. child = child.traverseNextNode(false, null, true);
  1950. }
  1951. },
  1952.  
  1953. refreshShowAsPercents: function()
  1954. {
  1955. this._updatePercentButton();
  1956. this.refreshVisibleData();
  1957. },
  1958.  
  1959. searchCanceled: function()
  1960. {
  1961. if (this._searchResults) {
  1962. for (var i = 0; i < this._searchResults.length; ++i) {
  1963. var profileNode = this._searchResults[i].profileNode;
  1964.  
  1965. delete profileNode._searchMatchedSelfColumn;
  1966. delete profileNode._searchMatchedTotalColumn;
  1967. delete profileNode._searchMatchedAverageColumn;
  1968. delete profileNode._searchMatchedCallsColumn;
  1969. delete profileNode._searchMatchedFunctionColumn;
  1970.  
  1971. profileNode.refresh();
  1972. }
  1973. }
  1974.  
  1975. delete this._searchFinishedCallback;
  1976. this._currentSearchResultIndex = -1;
  1977. this._searchResults = [];
  1978. },
  1979.  
  1980. performSearch: function(query, finishedCallback)
  1981. {
  1982.  
  1983. this.searchCanceled();
  1984.  
  1985. query = query.trim();
  1986.  
  1987. if (!query.length)
  1988. return;
  1989.  
  1990. this._searchFinishedCallback = finishedCallback;
  1991.  
  1992. var greaterThan = (query.startsWith(">"));
  1993. var lessThan = (query.startsWith("<"));
  1994. var equalTo = (query.startsWith("=") || ((greaterThan || lessThan) && query.indexOf("=") === 1));
  1995. var percentUnits = (query.lastIndexOf("%") === (query.length - 1));
  1996. var millisecondsUnits = (query.length > 2 && query.lastIndexOf("ms") === (query.length - 2));
  1997. var secondsUnits = (!millisecondsUnits && query.lastIndexOf("s") === (query.length - 1));
  1998.  
  1999. var queryNumber = parseFloat(query);
  2000. if (greaterThan || lessThan || equalTo) {
  2001. if (equalTo && (greaterThan || lessThan))
  2002. queryNumber = parseFloat(query.substring(2));
  2003. else
  2004. queryNumber = parseFloat(query.substring(1));
  2005. }
  2006.  
  2007. var queryNumberMilliseconds = (secondsUnits ? (queryNumber * 1000) : queryNumber);
  2008.  
  2009.  
  2010. if (!isNaN(queryNumber) && !(greaterThan || lessThan))
  2011. equalTo = true;
  2012.  
  2013. var matcher = new RegExp(query.escapeForRegExp(), "i");
  2014.  
  2015. function matchesQuery(  profileDataGridNode)
  2016. {
  2017. delete profileDataGridNode._searchMatchedSelfColumn;
  2018. delete profileDataGridNode._searchMatchedTotalColumn;
  2019. delete profileDataGridNode._searchMatchedAverageColumn;
  2020. delete profileDataGridNode._searchMatchedCallsColumn;
  2021. delete profileDataGridNode._searchMatchedFunctionColumn;
  2022.  
  2023. if (percentUnits) {
  2024. if (lessThan) {
  2025. if (profileDataGridNode.selfPercent < queryNumber)
  2026. profileDataGridNode._searchMatchedSelfColumn = true;
  2027. if (profileDataGridNode.totalPercent < queryNumber)
  2028. profileDataGridNode._searchMatchedTotalColumn = true;
  2029. if (profileDataGridNode.averagePercent < queryNumberMilliseconds)
  2030. profileDataGridNode._searchMatchedAverageColumn = true;
  2031. } else if (greaterThan) {
  2032. if (profileDataGridNode.selfPercent > queryNumber)
  2033. profileDataGridNode._searchMatchedSelfColumn = true;
  2034. if (profileDataGridNode.totalPercent > queryNumber)
  2035. profileDataGridNode._searchMatchedTotalColumn = true;
  2036. if (profileDataGridNode.averagePercent < queryNumberMilliseconds)
  2037. profileDataGridNode._searchMatchedAverageColumn = true;
  2038. }
  2039.  
  2040. if (equalTo) {
  2041. if (profileDataGridNode.selfPercent == queryNumber)
  2042. profileDataGridNode._searchMatchedSelfColumn = true;
  2043. if (profileDataGridNode.totalPercent == queryNumber)
  2044. profileDataGridNode._searchMatchedTotalColumn = true;
  2045. if (profileDataGridNode.averagePercent < queryNumberMilliseconds)
  2046. profileDataGridNode._searchMatchedAverageColumn = true;
  2047. }
  2048. } else if (millisecondsUnits || secondsUnits) {
  2049. if (lessThan) {
  2050. if (profileDataGridNode.selfTime < queryNumberMilliseconds)
  2051. profileDataGridNode._searchMatchedSelfColumn = true;
  2052. if (profileDataGridNode.totalTime < queryNumberMilliseconds)
  2053. profileDataGridNode._searchMatchedTotalColumn = true;
  2054. if (profileDataGridNode.averageTime < queryNumberMilliseconds)
  2055. profileDataGridNode._searchMatchedAverageColumn = true;
  2056. } else if (greaterThan) {
  2057. if (profileDataGridNode.selfTime > queryNumberMilliseconds)
  2058. profileDataGridNode._searchMatchedSelfColumn = true;
  2059. if (profileDataGridNode.totalTime > queryNumberMilliseconds)
  2060. profileDataGridNode._searchMatchedTotalColumn = true;
  2061. if (profileDataGridNode.averageTime > queryNumberMilliseconds)
  2062. profileDataGridNode._searchMatchedAverageColumn = true;
  2063. }
  2064.  
  2065. if (equalTo) {
  2066. if (profileDataGridNode.selfTime == queryNumberMilliseconds)
  2067. profileDataGridNode._searchMatchedSelfColumn = true;
  2068. if (profileDataGridNode.totalTime == queryNumberMilliseconds)
  2069. profileDataGridNode._searchMatchedTotalColumn = true;
  2070. if (profileDataGridNode.averageTime == queryNumberMilliseconds)
  2071. profileDataGridNode._searchMatchedAverageColumn = true;
  2072. }
  2073. } else {
  2074. if (equalTo && profileDataGridNode.numberOfCalls == queryNumber)
  2075. profileDataGridNode._searchMatchedCallsColumn = true;
  2076. if (greaterThan && profileDataGridNode.numberOfCalls > queryNumber)
  2077. profileDataGridNode._searchMatchedCallsColumn = true;
  2078. if (lessThan && profileDataGridNode.numberOfCalls < queryNumber)
  2079. profileDataGridNode._searchMatchedCallsColumn = true;
  2080. }
  2081.  
  2082. if (profileDataGridNode.functionName.match(matcher) || profileDataGridNode.url.match(matcher))
  2083. profileDataGridNode._searchMatchedFunctionColumn = true;
  2084.  
  2085. if (profileDataGridNode._searchMatchedSelfColumn ||
  2086. profileDataGridNode._searchMatchedTotalColumn ||
  2087. profileDataGridNode._searchMatchedAverageColumn ||
  2088. profileDataGridNode._searchMatchedCallsColumn ||
  2089. profileDataGridNode._searchMatchedFunctionColumn)
  2090. {
  2091. profileDataGridNode.refresh();
  2092. return true;
  2093. }
  2094.  
  2095. return false;
  2096. }
  2097.  
  2098. var current = this.profileDataGridTree.children[0];
  2099.  
  2100. while (current) {
  2101. if (matchesQuery(current)) {
  2102. this._searchResults.push({ profileNode: current });
  2103. }
  2104.  
  2105. current = current.traverseNextNode(false, null, false);
  2106. }
  2107.  
  2108. finishedCallback(this, this._searchResults.length);
  2109. },
  2110.  
  2111. jumpToFirstSearchResult: function()
  2112. {
  2113. if (!this._searchResults || !this._searchResults.length)
  2114. return;
  2115. this._currentSearchResultIndex = 0;
  2116. this._jumpToSearchResult(this._currentSearchResultIndex);
  2117. },
  2118.  
  2119. jumpToLastSearchResult: function()
  2120. {
  2121. if (!this._searchResults || !this._searchResults.length)
  2122. return;
  2123. this._currentSearchResultIndex = (this._searchResults.length - 1);
  2124. this._jumpToSearchResult(this._currentSearchResultIndex);
  2125. },
  2126.  
  2127. jumpToNextSearchResult: function()
  2128. {
  2129. if (!this._searchResults || !this._searchResults.length)
  2130. return;
  2131. if (++this._currentSearchResultIndex >= this._searchResults.length)
  2132. this._currentSearchResultIndex = 0;
  2133. this._jumpToSearchResult(this._currentSearchResultIndex);
  2134. },
  2135.  
  2136. jumpToPreviousSearchResult: function()
  2137. {
  2138. if (!this._searchResults || !this._searchResults.length)
  2139. return;
  2140. if (--this._currentSearchResultIndex < 0)
  2141. this._currentSearchResultIndex = (this._searchResults.length - 1);
  2142. this._jumpToSearchResult(this._currentSearchResultIndex);
  2143. },
  2144.  
  2145. showingFirstSearchResult: function()
  2146. {
  2147. return (this._currentSearchResultIndex === 0);
  2148. },
  2149.  
  2150. showingLastSearchResult: function()
  2151. {
  2152. return (this._searchResults && this._currentSearchResultIndex === (this._searchResults.length - 1));
  2153. },
  2154.  
  2155. _jumpToSearchResult: function(index)
  2156. {
  2157. var searchResult = this._searchResults[index];
  2158. if (!searchResult)
  2159. return;
  2160.  
  2161. var profileNode = searchResult.profileNode;
  2162. profileNode.revealAndSelect();
  2163. },
  2164.  
  2165. _changeView: function()
  2166. {
  2167. if (!this.profile)
  2168. return;
  2169.  
  2170. switch (this.viewSelectComboBox.selectedOption().value) {
  2171. case WebInspector.CPUProfileView._TypeTree:
  2172. this.profileDataGridTree = this.topDownProfileDataGridTree;
  2173. this._sortProfile();
  2174. this._viewType.set(WebInspector.CPUProfileView._TypeTree);
  2175. break;
  2176. case WebInspector.CPUProfileView._TypeHeavy:
  2177. this.profileDataGridTree = this.bottomUpProfileDataGridTree;
  2178. this._sortProfile();
  2179. this._viewType.set(WebInspector.CPUProfileView._TypeHeavy);
  2180. }
  2181.  
  2182. if (!this.currentQuery || !this._searchFinishedCallback || !this._searchResults)
  2183. return;
  2184.  
  2185.  
  2186.  
  2187.  
  2188. this._searchFinishedCallback(this, -this._searchResults.length);
  2189. this.performSearch(this.currentQuery, this._searchFinishedCallback);
  2190. },
  2191.  
  2192. _percentClicked: function(event)
  2193. {
  2194. var currentState = this.showSelfTimeAsPercent.get() && this.showTotalTimeAsPercent.get() && this.showAverageTimeAsPercent.get();
  2195. this.showSelfTimeAsPercent.set(!currentState);
  2196. this.showTotalTimeAsPercent.set(!currentState);
  2197. this.showAverageTimeAsPercent.set(!currentState);
  2198. this.refreshShowAsPercents();
  2199. },
  2200.  
  2201. _updatePercentButton: function()
  2202. {
  2203. if (this.showSelfTimeAsPercent.get() && this.showTotalTimeAsPercent.get() && this.showAverageTimeAsPercent.get()) {
  2204. this.percentButton.title = WebInspector.UIString("Show absolute total and self times.");
  2205. this.percentButton.toggled = true;
  2206. } else {
  2207. this.percentButton.title = WebInspector.UIString("Show total and self times as percentages.");
  2208. this.percentButton.toggled = false;
  2209. }
  2210. },
  2211.  
  2212. _focusClicked: function(event)
  2213. {
  2214. if (!this.dataGrid.selectedNode)
  2215. return;
  2216.  
  2217. this.resetButton.visible = true;
  2218. this.profileDataGridTree.focus(this.dataGrid.selectedNode);
  2219. this.refresh();
  2220. this.refreshVisibleData();
  2221. },
  2222.  
  2223. _excludeClicked: function(event)
  2224. {
  2225. var selectedNode = this.dataGrid.selectedNode
  2226.  
  2227. if (!selectedNode)
  2228. return;
  2229.  
  2230. selectedNode.deselect();
  2231.  
  2232. this.resetButton.visible = true;
  2233. this.profileDataGridTree.exclude(selectedNode);
  2234. this.refresh();
  2235. this.refreshVisibleData();
  2236. },
  2237.  
  2238. _resetClicked: function(event)
  2239. {
  2240. this.resetButton.visible = false;
  2241. this.profileDataGridTree.restore();
  2242. this._linkifier.reset();
  2243. this.refresh();
  2244. this.refreshVisibleData();
  2245. },
  2246.  
  2247. _dataGridNodeSelected: function(node)
  2248. {
  2249. this.focusButton.setEnabled(true);
  2250. this.excludeButton.setEnabled(true);
  2251. },
  2252.  
  2253. _dataGridNodeDeselected: function(node)
  2254. {
  2255. this.focusButton.setEnabled(false);
  2256. this.excludeButton.setEnabled(false);
  2257. },
  2258.  
  2259. _sortProfile: function()
  2260. {
  2261. var sortAscending = this.dataGrid.sortOrder === "ascending";
  2262. var sortColumnIdentifier = this.dataGrid.sortColumnIdentifier;
  2263. var sortProperty = {
  2264. "average": "averageTime",
  2265. "self": "selfTime",
  2266. "total": "totalTime",
  2267. "calls": "numberOfCalls",
  2268. "function": "functionName"
  2269. }[sortColumnIdentifier];
  2270.  
  2271. this.profileDataGridTree.sort(WebInspector.ProfileDataGridTree.propertyComparator(sortProperty, sortAscending));
  2272.  
  2273. this.refresh();
  2274. },
  2275.  
  2276. _mouseDownInDataGrid: function(event)
  2277. {
  2278. if (event.detail < 2)
  2279. return;
  2280.  
  2281. var cell = event.target.enclosingNodeOrSelfWithNodeName("td");
  2282. if (!cell || (!cell.hasStyleClass("total-column") && !cell.hasStyleClass("self-column") && !cell.hasStyleClass("average-column")))
  2283. return;
  2284.  
  2285. if (cell.hasStyleClass("total-column"))
  2286. this.showTotalTimeAsPercent.set(!this.showTotalTimeAsPercent.get());
  2287. else if (cell.hasStyleClass("self-column"))
  2288. this.showSelfTimeAsPercent.set(!this.showSelfTimeAsPercent.get());
  2289. else if (cell.hasStyleClass("average-column"))
  2290. this.showAverageTimeAsPercent.set(!this.showAverageTimeAsPercent.get());
  2291.  
  2292. this.refreshShowAsPercents();
  2293.  
  2294. event.consume(true);
  2295. },
  2296.  
  2297. _assignParentsInProfile: function()
  2298. {
  2299. var head = this.profile.head;
  2300. head.parent = null;
  2301. head.head = null;
  2302. var nodesToTraverse = [ { parent: head, children: head.children } ];
  2303. while (nodesToTraverse.length > 0) {
  2304. var pair = nodesToTraverse.shift();
  2305. var parent = pair.parent;
  2306. var children = pair.children;
  2307. var length = children.length;
  2308. for (var i = 0; i < length; ++i) {
  2309. children[i].head = head;
  2310. children[i].parent = parent;
  2311. if (children[i].children.length > 0)
  2312. nodesToTraverse.push({ parent: children[i], children: children[i].children });
  2313. }
  2314. }
  2315. },
  2316.  
  2317. __proto__: WebInspector.View.prototype
  2318. }
  2319.  
  2320.  
  2321. WebInspector.CPUProfileType = function()
  2322. {
  2323. WebInspector.ProfileType.call(this, WebInspector.CPUProfileType.TypeId, WebInspector.UIString("Collect JavaScript CPU Profile"));
  2324. this._recording = false;
  2325. WebInspector.CPUProfileType.instance = this;
  2326. }
  2327.  
  2328. WebInspector.CPUProfileType.TypeId = "CPU";
  2329.  
  2330. WebInspector.CPUProfileType.prototype = {
  2331. get buttonTooltip()
  2332. {
  2333. return this._recording ? WebInspector.UIString("Stop CPU profiling.") : WebInspector.UIString("Start CPU profiling.");
  2334. },
  2335.  
  2336.  
  2337. buttonClicked: function()
  2338. {
  2339. if (this._recording) {
  2340. this.stopRecordingProfile();
  2341. return false;
  2342. } else {
  2343. this.startRecordingProfile();
  2344. return true;
  2345. }
  2346. },
  2347.  
  2348. get treeItemTitle()
  2349. {
  2350. return WebInspector.UIString("CPU PROFILES");
  2351. },
  2352.  
  2353. get description()
  2354. {
  2355. return WebInspector.UIString("CPU profiles show where the execution time is spent in your page's JavaScript functions.");
  2356. },
  2357.  
  2358. isRecordingProfile: function()
  2359. {
  2360. return this._recording;
  2361. },
  2362.  
  2363. startRecordingProfile: function()
  2364. {
  2365. this._recording = true;
  2366. WebInspector.userMetrics.ProfilesCPUProfileTaken.record();
  2367. ProfilerAgent.start();
  2368. },
  2369.  
  2370. stopRecordingProfile: function()
  2371. {
  2372. this._recording = false;
  2373. ProfilerAgent.stop();
  2374. },
  2375.  
  2376. setRecordingProfile: function(isProfiling)
  2377. {
  2378. this._recording = isProfiling;
  2379. },
  2380.  
  2381.  
  2382. createTemporaryProfile: function(title)
  2383. {
  2384. title = title || WebInspector.UIString("Recording\u2026");
  2385. return new WebInspector.CPUProfileHeader(this, title);
  2386. },
  2387.  
  2388.  
  2389. createProfile: function(profile)
  2390. {
  2391. return new WebInspector.CPUProfileHeader(this, profile.title, profile.uid);
  2392. },
  2393.  
  2394. __proto__: WebInspector.ProfileType.prototype
  2395. }
  2396.  
  2397.  
  2398. WebInspector.CPUProfileHeader = function(type, title, uid)
  2399. {
  2400. WebInspector.ProfileHeader.call(this, type, title, uid);
  2401. }
  2402.  
  2403. WebInspector.CPUProfileHeader.prototype = {
  2404.  
  2405. createSidebarTreeElement: function()
  2406. {
  2407. return new WebInspector.ProfileSidebarTreeElement(this, WebInspector.UIString("Profile %d"), "profile-sidebar-tree-item");
  2408. },
  2409.  
  2410.  
  2411. createView: function(profilesPanel)
  2412. {
  2413. return new WebInspector.CPUProfileView(this);
  2414. },
  2415.  
  2416. __proto__: WebInspector.ProfileHeader.prototype
  2417. }
  2418. ;
  2419.  
  2420.  
  2421.  
  2422. WebInspector.CSSSelectorDataGridNode = function(profileView, data)
  2423. {
  2424. WebInspector.DataGridNode.call(this, data, false);
  2425. this._profileView = profileView;
  2426. }
  2427.  
  2428. WebInspector.CSSSelectorDataGridNode.prototype = {
  2429. get data()
  2430. {
  2431. var data = {};
  2432. data.selector = this._data.selector;
  2433. data.matches = this._data.matchCount;
  2434.  
  2435. if (this._profileView.showTimeAsPercent.get())
  2436. data.time = Number(this._data.timePercent).toFixed(1) + "%";
  2437. else
  2438. data.time = Number.secondsToString(this._data.time / 1000, true);
  2439.  
  2440. return data;
  2441. },
  2442.  
  2443. get rawData()
  2444. {
  2445. return this._data;
  2446. },
  2447.  
  2448. createCell: function(columnIdentifier)
  2449. {
  2450. var cell = WebInspector.DataGridNode.prototype.createCell.call(this, columnIdentifier);
  2451. if (columnIdentifier === "selector" && cell.firstChild) {
  2452. cell.firstChild.title = this.rawData.selector;
  2453. return cell;
  2454. }
  2455.  
  2456. if (columnIdentifier !== "source")
  2457. return cell;
  2458.  
  2459. cell.removeChildren();
  2460.  
  2461. if (this.rawData.url) {
  2462. var wrapperDiv = cell.createChild("div");
  2463. wrapperDiv.appendChild(WebInspector.linkifyResourceAsNode(this.rawData.url, this.rawData.lineNumber));
  2464. }
  2465.  
  2466. return cell;
  2467. },
  2468.  
  2469. __proto__: WebInspector.DataGridNode.prototype
  2470. }
  2471.  
  2472.  
  2473. WebInspector.CSSSelectorProfileView = function(profile)
  2474. {
  2475. WebInspector.View.call(this);
  2476.  
  2477. this.element.addStyleClass("profile-view");
  2478.  
  2479. this.showTimeAsPercent = WebInspector.settings.createSetting("selectorProfilerShowTimeAsPercent", true);
  2480.  
  2481. var columns = { "selector": { title: WebInspector.UIString("Selector"), width: "550px", sortable: true },
  2482. "source": { title: WebInspector.UIString("Source"), width: "100px", sortable: true },
  2483. "time": { title: WebInspector.UIString("Total"), width: "72px", sort: "descending", sortable: true },
  2484. "matches": { title: WebInspector.UIString("Matches"), width: "72px", sortable: true } };
  2485.  
  2486. this.dataGrid = new WebInspector.DataGrid(columns);
  2487. this.dataGrid.element.addStyleClass("selector-profile-view");
  2488. this.dataGrid.addEventListener("sorting changed", this._sortProfile, this);
  2489. this.dataGrid.element.addEventListener("mousedown", this._mouseDownInDataGrid.bind(this), true);
  2490. this.dataGrid.show(this.element);
  2491.  
  2492. this.percentButton = new WebInspector.StatusBarButton("", "percent-time-status-bar-item");
  2493. this.percentButton.addEventListener("click", this._percentClicked, this);
  2494.  
  2495. this.profile = profile;
  2496.  
  2497. this._createProfileNodes();
  2498. this._sortProfile();
  2499. this._updatePercentButton();
  2500. }
  2501.  
  2502. WebInspector.CSSSelectorProfileView.prototype = {
  2503. get statusBarItems()
  2504. {
  2505. return [this.percentButton.element];
  2506. },
  2507.  
  2508. get profile()
  2509. {
  2510. return this._profile;
  2511. },
  2512.  
  2513. set profile(profile)
  2514. {
  2515. this._profile = profile;
  2516. },
  2517.  
  2518. _createProfileNodes: function()
  2519. {
  2520. var data = this.profile.data;
  2521. if (!data) {
  2522.  
  2523. return;
  2524. }
  2525.  
  2526. this.profile.children = [];
  2527. for (var i = 0; i < data.length; ++i) {
  2528. data[i].timePercent = data[i].time * 100 / this.profile.totalTime;
  2529. var node = new WebInspector.CSSSelectorDataGridNode(this, data[i]);
  2530. this.profile.children.push(node);
  2531. }
  2532. },
  2533.  
  2534. rebuildGridItems: function()
  2535. {
  2536. this.dataGrid.rootNode().removeChildren();
  2537.  
  2538. var children = this.profile.children;
  2539. var count = children.length;
  2540.  
  2541. for (var index = 0; index < count; ++index)
  2542. this.dataGrid.rootNode().appendChild(children[index]);
  2543. },
  2544.  
  2545. refreshData: function()
  2546. {
  2547. var child = this.dataGrid.rootNode().children[0];
  2548. while (child) {
  2549. child.refresh();
  2550. child = child.traverseNextNode(false, null, true);
  2551. }
  2552. },
  2553.  
  2554. refreshShowAsPercents: function()
  2555. {
  2556. this._updatePercentButton();
  2557. this.refreshData();
  2558. },
  2559.  
  2560. _percentClicked: function(event)
  2561. {
  2562. this.showTimeAsPercent.set(!this.showTimeAsPercent.get());
  2563. this.refreshShowAsPercents();
  2564. },
  2565.  
  2566. _updatePercentButton: function()
  2567. {
  2568. if (this.showTimeAsPercent.get()) {
  2569. this.percentButton.title = WebInspector.UIString("Show absolute times.");
  2570. this.percentButton.toggled = true;
  2571. } else {
  2572. this.percentButton.title = WebInspector.UIString("Show times as percentages.");
  2573. this.percentButton.toggled = false;
  2574. }
  2575. },
  2576.  
  2577. _sortProfile: function()
  2578. {
  2579. var sortAscending = this.dataGrid.sortOrder === "ascending";
  2580. var sortColumnIdentifier = this.dataGrid.sortColumnIdentifier;
  2581.  
  2582. function selectorComparator(a, b)
  2583. {
  2584. var result = b.rawData.selector.localeCompare(a.rawData.selector);
  2585. return sortAscending ? -result : result;
  2586. }
  2587.  
  2588. function sourceComparator(a, b)
  2589. {
  2590. var aRawData = a.rawData;
  2591. var bRawData = b.rawData;
  2592. var result = bRawData.url.localeCompare(aRawData.url);
  2593. if (!result)
  2594. result = bRawData.lineNumber - aRawData.lineNumber;
  2595. return sortAscending ? -result : result;
  2596. }
  2597.  
  2598. function timeComparator(a, b)
  2599. {
  2600. const result = b.rawData.time - a.rawData.time;
  2601. return sortAscending ? -result : result;
  2602. }
  2603.  
  2604. function matchesComparator(a, b)
  2605. {
  2606. const result = b.rawData.matchCount - a.rawData.matchCount;
  2607. return sortAscending ? -result : result;
  2608. }
  2609.  
  2610. var comparator;
  2611. switch (sortColumnIdentifier) {
  2612. case "time":
  2613. comparator = timeComparator;
  2614. break;
  2615. case "matches":
  2616. comparator = matchesComparator;
  2617. break;
  2618. case "selector":
  2619. comparator = selectorComparator;
  2620. break;
  2621. case "source":
  2622. comparator = sourceComparator;
  2623. break;
  2624. }
  2625.  
  2626. this.profile.children.sort(comparator);
  2627.  
  2628. this.rebuildGridItems();
  2629. },
  2630.  
  2631. _mouseDownInDataGrid: function(event)
  2632. {
  2633. if (event.detail < 2)
  2634. return;
  2635.  
  2636. var cell = event.target.enclosingNodeOrSelfWithNodeName("td");
  2637. if (!cell)
  2638. return;
  2639.  
  2640. if (cell.hasStyleClass("time-column"))
  2641. this.showTimeAsPercent.set(!this.showTimeAsPercent.get());
  2642. else
  2643. return;
  2644.  
  2645. this.refreshShowAsPercents();
  2646.  
  2647. event.consume(true);
  2648. },
  2649.  
  2650. __proto__: WebInspector.View.prototype
  2651. }
  2652.  
  2653.  
  2654. WebInspector.CSSSelectorProfileType = function()
  2655. {
  2656. WebInspector.ProfileType.call(this, WebInspector.CSSSelectorProfileType.TypeId, WebInspector.UIString("Collect CSS Selector Profile"));
  2657. this._recording = false;
  2658. this._profileUid = 1;
  2659. WebInspector.CSSSelectorProfileType.instance = this;
  2660. }
  2661.  
  2662. WebInspector.CSSSelectorProfileType.TypeId = "SELECTOR";
  2663.  
  2664. WebInspector.CSSSelectorProfileType.prototype = {
  2665. get buttonTooltip()
  2666. {
  2667. return this._recording ? WebInspector.UIString("Stop CSS selector profiling.") : WebInspector.UIString("Start CSS selector profiling.");
  2668. },
  2669.  
  2670.  
  2671. buttonClicked: function(profilesPanel)
  2672. {
  2673. if (this._recording) {
  2674. this._stopRecordingProfile(profilesPanel);
  2675. return false;
  2676. } else {
  2677. this._startRecordingProfile(profilesPanel);
  2678. return true;
  2679. }
  2680. },
  2681.  
  2682. get treeItemTitle()
  2683. {
  2684. return WebInspector.UIString("CSS SELECTOR PROFILES");
  2685. },
  2686.  
  2687. get description()
  2688. {
  2689. return WebInspector.UIString("CSS selector profiles show how long the selector matching has taken in total and how many times a certain selector has matched DOM elements (the results are approximate due to matching algorithm optimizations.)");
  2690. },
  2691.  
  2692. reset: function()
  2693. {
  2694. this._profileUid = 1;
  2695. },
  2696.  
  2697. setRecordingProfile: function(isProfiling)
  2698. {
  2699. this._recording = isProfiling;
  2700. },
  2701.  
  2702.  
  2703. _startRecordingProfile: function(profilesPanel)
  2704. {
  2705. this._recording = true;
  2706. CSSAgent.startSelectorProfiler();
  2707. profilesPanel.setRecordingProfile(WebInspector.CSSSelectorProfileType.TypeId, true);
  2708. },
  2709.  
  2710.  
  2711. _stopRecordingProfile: function(profilesPanel)
  2712. {
  2713.  
  2714. function callback(error, profile)
  2715. {
  2716. if (error)
  2717. return;
  2718.  
  2719. var uid = this._profileUid++;
  2720. var title = WebInspector.UIString("Profile %d", uid) + String.sprintf(" (%s)", Number.secondsToString(profile.totalTime / 1000));
  2721. var profileHeader = new WebInspector.CSSProfileHeader(this, title, uid, profile);
  2722. profilesPanel.addProfileHeader(profileHeader);
  2723. profilesPanel.setRecordingProfile(WebInspector.CSSSelectorProfileType.TypeId, false);
  2724. }
  2725.  
  2726. this._recording = false;
  2727. CSSAgent.stopSelectorProfiler(callback.bind(this));
  2728. },
  2729.  
  2730.  
  2731. createTemporaryProfile: function(title)
  2732. {
  2733. title = title || WebInspector.UIString("Recording\u2026");
  2734. return new WebInspector.CSSProfileHeader(this, title);
  2735. },
  2736.  
  2737. __proto__: WebInspector.ProfileType.prototype
  2738. }
  2739.  
  2740.  
  2741.  
  2742. WebInspector.CSSProfileHeader = function(type, title, uid, protocolData)
  2743. {
  2744. WebInspector.ProfileHeader.call(this, type, title, uid);
  2745. this._protocolData = protocolData;
  2746. }
  2747.  
  2748. WebInspector.CSSProfileHeader.prototype = {
  2749.  
  2750. createSidebarTreeElement: function()
  2751. {
  2752. return new WebInspector.ProfileSidebarTreeElement(this, this.title, "profile-sidebar-tree-item");
  2753. },
  2754.  
  2755.  
  2756. createView: function(profilesPanel)
  2757. {
  2758. var profile =   (this._protocolData);
  2759. return new WebInspector.CSSSelectorProfileView(profile);
  2760. },
  2761.  
  2762. __proto__: WebInspector.ProfileHeader.prototype
  2763. }
  2764. ;
  2765.  
  2766.  
  2767.  
  2768. WebInspector.HeapSnapshotArraySlice = function(array, start, end)
  2769. {
  2770. this._array = array;
  2771. this._start = start;
  2772. this.length = end - start;
  2773. }
  2774.  
  2775. WebInspector.HeapSnapshotArraySlice.prototype = {
  2776. item: function(index)
  2777. {
  2778. return this._array[this._start + index];
  2779. },
  2780.  
  2781. slice: function(start, end)
  2782. {
  2783. if (typeof end === "undefined")
  2784. end = this.length;
  2785. return this._array.subarray(this._start + start, this._start + end);
  2786. }
  2787. }
  2788.  
  2789.  
  2790. WebInspector.HeapSnapshotEdge = function(snapshot, edges, edgeIndex)
  2791. {
  2792. this._snapshot = snapshot;
  2793. this._edges = edges;
  2794. this.edgeIndex = edgeIndex || 0;
  2795. }
  2796.  
  2797. WebInspector.HeapSnapshotEdge.prototype = {
  2798. clone: function()
  2799. {
  2800. return new WebInspector.HeapSnapshotEdge(this._snapshot, this._edges, this.edgeIndex);
  2801. },
  2802.  
  2803. hasStringName: function()
  2804. {
  2805. if (!this.isShortcut())
  2806. return this._hasStringName();
  2807. return isNaN(parseInt(this._name(), 10));
  2808. },
  2809.  
  2810. isElement: function()
  2811. {
  2812. return this._type() === this._snapshot._edgeElementType;
  2813. },
  2814.  
  2815. isHidden: function()
  2816. {
  2817. return this._type() === this._snapshot._edgeHiddenType;
  2818. },
  2819.  
  2820. isWeak: function()
  2821. {
  2822. return this._type() === this._snapshot._edgeWeakType;
  2823. },
  2824.  
  2825. isInternal: function()
  2826. {
  2827. return this._type() === this._snapshot._edgeInternalType;
  2828. },
  2829.  
  2830. isInvisible: function()
  2831. {
  2832. return this._type() === this._snapshot._edgeInvisibleType;
  2833. },
  2834.  
  2835. isShortcut: function()
  2836. {
  2837. return this._type() === this._snapshot._edgeShortcutType;
  2838. },
  2839.  
  2840. name: function()
  2841. {
  2842. if (!this.isShortcut())
  2843. return this._name();
  2844. var numName = parseInt(this._name(), 10);
  2845. return isNaN(numName) ? this._name() : numName;
  2846. },
  2847.  
  2848. node: function()
  2849. {
  2850. return new WebInspector.HeapSnapshotNode(this._snapshot, this.nodeIndex());
  2851. },
  2852.  
  2853. nodeIndex: function()
  2854. {
  2855. return this._edges.item(this.edgeIndex + this._snapshot._edgeToNodeOffset);
  2856. },
  2857.  
  2858. rawEdges: function()
  2859. {
  2860. return this._edges;
  2861. },
  2862.  
  2863. toString: function()
  2864. {
  2865. var name = this.name();
  2866. switch (this.type()) {
  2867. case "context": return "->" + name;
  2868. case "element": return "[" + name + "]";
  2869. case "weak": return "[[" + name + "]]";
  2870. case "property":
  2871. return name.indexOf(" ") === -1 ? "." + name : "[\"" + name + "\"]";
  2872. case "shortcut":
  2873. if (typeof name === "string")
  2874. return name.indexOf(" ") === -1 ? "." + name : "[\"" + name + "\"]";
  2875. else
  2876. return "[" + name + "]";
  2877. case "internal":
  2878. case "hidden":
  2879. case "invisible":
  2880. return "{" + name + "}";
  2881. };
  2882. return "?" + name + "?";
  2883. },
  2884.  
  2885. type: function()
  2886. {
  2887. return this._snapshot._edgeTypes[this._type()];
  2888. },
  2889.  
  2890. _hasStringName: function()
  2891. {
  2892. return !this.isElement() && !this.isHidden() && !this.isWeak();
  2893. },
  2894.  
  2895. _name: function()
  2896. {
  2897. return this._hasStringName() ? this._snapshot._strings[this._nameOrIndex()] : this._nameOrIndex();
  2898. },
  2899.  
  2900. _nameOrIndex: function()
  2901. {
  2902. return this._edges.item(this.edgeIndex + this._snapshot._edgeNameOffset);
  2903. },
  2904.  
  2905. _type: function()
  2906. {
  2907. return this._edges.item(this.edgeIndex + this._snapshot._edgeTypeOffset);
  2908. }
  2909. };
  2910.  
  2911.  
  2912. WebInspector.HeapSnapshotEdgeIterator = function(edge)
  2913. {
  2914. this.edge = edge;
  2915. }
  2916.  
  2917. WebInspector.HeapSnapshotEdgeIterator.prototype = {
  2918. first: function()
  2919. {
  2920. this.edge.edgeIndex = 0;
  2921. },
  2922.  
  2923. hasNext: function()
  2924. {
  2925. return this.edge.edgeIndex < this.edge._edges.length;
  2926. },
  2927.  
  2928. index: function()
  2929. {
  2930. return this.edge.edgeIndex;
  2931. },
  2932.  
  2933. setIndex: function(newIndex)
  2934. {
  2935. this.edge.edgeIndex = newIndex;
  2936. },
  2937.  
  2938. item: function()
  2939. {
  2940. return this.edge;
  2941. },
  2942.  
  2943. next: function()
  2944. {
  2945. this.edge.edgeIndex += this.edge._snapshot._edgeFieldsCount;
  2946. }
  2947. };
  2948.  
  2949.  
  2950. WebInspector.HeapSnapshotRetainerEdge = function(snapshot, retainedNodeIndex, retainerIndex)
  2951. {
  2952. this._snapshot = snapshot;
  2953. this._retainedNodeIndex = retainedNodeIndex;
  2954.  
  2955. var retainedNodeOrdinal = retainedNodeIndex / snapshot._nodeFieldCount;
  2956. this._firstRetainer = snapshot._firstRetainerIndex[retainedNodeOrdinal];
  2957. this._retainersCount = snapshot._firstRetainerIndex[retainedNodeOrdinal + 1] - this._firstRetainer;
  2958.  
  2959. this.setRetainerIndex(retainerIndex);
  2960. }
  2961.  
  2962. WebInspector.HeapSnapshotRetainerEdge.prototype = {
  2963. clone: function()
  2964. {
  2965. return new WebInspector.HeapSnapshotRetainerEdge(this._snapshot, this._retainedNodeIndex, this.retainerIndex());
  2966. },
  2967.  
  2968. hasStringName: function()
  2969. {
  2970. return this._edge().hasStringName();
  2971. },
  2972.  
  2973. isElement: function()
  2974. {
  2975. return this._edge().isElement();
  2976. },
  2977.  
  2978. isHidden: function()
  2979. {
  2980. return this._edge().isHidden();
  2981. },
  2982.  
  2983. isInternal: function()
  2984. {
  2985. return this._edge().isInternal();
  2986. },
  2987.  
  2988. isInvisible: function()
  2989. {
  2990. return this._edge().isInvisible();
  2991. },
  2992.  
  2993. isShortcut: function()
  2994. {
  2995. return this._edge().isShortcut();
  2996. },
  2997.  
  2998. isWeak: function()
  2999. {
  3000. return this._edge().isWeak();
  3001. },
  3002.  
  3003. name: function()
  3004. {
  3005. return this._edge().name();
  3006. },
  3007.  
  3008. node: function()
  3009. {
  3010. return this._node();
  3011. },
  3012.  
  3013. nodeIndex: function()
  3014. {
  3015. return this._nodeIndex;
  3016. },
  3017.  
  3018. retainerIndex: function()
  3019. {
  3020. return this._retainerIndex;
  3021. },
  3022.  
  3023. setRetainerIndex: function(newIndex)
  3024. {
  3025. if (newIndex !== this._retainerIndex) {
  3026. this._retainerIndex = newIndex;
  3027. this.edgeIndex = newIndex;
  3028. }
  3029. },
  3030.  
  3031. set edgeIndex(edgeIndex)
  3032. {
  3033. var retainerIndex = this._firstRetainer + edgeIndex;
  3034. this._globalEdgeIndex = this._snapshot._retainingEdges[retainerIndex];
  3035. this._nodeIndex = this._snapshot._retainingNodes[retainerIndex];
  3036. delete this._edgeInstance;
  3037. delete this._nodeInstance;
  3038. },
  3039.  
  3040. _node: function()
  3041. {
  3042. if (!this._nodeInstance)
  3043. this._nodeInstance = new WebInspector.HeapSnapshotNode(this._snapshot, this._nodeIndex);
  3044. return this._nodeInstance;
  3045. },
  3046.  
  3047. _edge: function()
  3048. {
  3049. if (!this._edgeInstance) {
  3050. var edgeIndex = this._globalEdgeIndex - this._node()._edgeIndexesStart();
  3051. this._edgeInstance = new WebInspector.HeapSnapshotEdge(this._snapshot, this._node().rawEdges(), edgeIndex);
  3052. }
  3053. return this._edgeInstance;
  3054. },
  3055.  
  3056. toString: function()
  3057. {
  3058. return this._edge().toString();
  3059. },
  3060.  
  3061. type: function()
  3062. {
  3063. return this._edge().type();
  3064. }
  3065. }
  3066.  
  3067.  
  3068. WebInspector.HeapSnapshotRetainerEdgeIterator = function(retainer)
  3069. {
  3070. this.retainer = retainer;
  3071. }
  3072.  
  3073. WebInspector.HeapSnapshotRetainerEdgeIterator.prototype = {
  3074. first: function()
  3075. {
  3076. this.retainer.setRetainerIndex(0);
  3077. },
  3078.  
  3079. hasNext: function()
  3080. {
  3081. return this.retainer.retainerIndex() < this.retainer._retainersCount;
  3082. },
  3083.  
  3084. index: function()
  3085. {
  3086. return this.retainer.retainerIndex();
  3087. },
  3088.  
  3089. setIndex: function(newIndex)
  3090. {
  3091. this.retainer.setRetainerIndex(newIndex);
  3092. },
  3093.  
  3094. item: function()
  3095. {
  3096. return this.retainer;
  3097. },
  3098.  
  3099. next: function()
  3100. {
  3101. this.retainer.setRetainerIndex(this.retainer.retainerIndex() + 1);
  3102. }
  3103. };
  3104.  
  3105.  
  3106. WebInspector.HeapSnapshotNode = function(snapshot, nodeIndex)
  3107. {
  3108. this._snapshot = snapshot;
  3109. this._firstNodeIndex = nodeIndex;
  3110. this.nodeIndex = nodeIndex;
  3111. }
  3112.  
  3113. WebInspector.HeapSnapshotNode.prototype = {
  3114. canBeQueried: function()
  3115. {
  3116. var flags = this._snapshot._flagsOfNode(this);
  3117. return !!(flags & this._snapshot._nodeFlags.canBeQueried);
  3118. },
  3119.  
  3120. isPageObject: function()
  3121. {
  3122. var flags = this._snapshot._flagsOfNode(this);
  3123. return !!(flags & this._snapshot._nodeFlags.pageObject);
  3124. },
  3125.  
  3126. distanceToWindow: function()
  3127. {
  3128. return this._snapshot._distancesToWindow[this.nodeIndex / this._snapshot._nodeFieldCount];
  3129. },
  3130.  
  3131. className: function()
  3132. {
  3133. var type = this.type();
  3134. switch (type) {
  3135. case "hidden":
  3136. return WebInspector.UIString("(system)");
  3137. case "object":
  3138. case "native":
  3139. return this.name();
  3140. case "code":
  3141. return WebInspector.UIString("(compiled code)");
  3142. default:
  3143. return "(" + type + ")";
  3144. }
  3145. },
  3146.  
  3147. classIndex: function()
  3148. {
  3149. var snapshot = this._snapshot;
  3150. var nodes = snapshot._nodes;
  3151. var type = nodes[this.nodeIndex + snapshot._nodeTypeOffset];;
  3152. if (type === snapshot._nodeObjectType || type === snapshot._nodeNativeType)
  3153. return nodes[this.nodeIndex + snapshot._nodeNameOffset];
  3154. return -1 - type;
  3155. },
  3156.  
  3157. dominatorIndex: function()
  3158. {
  3159. var nodeFieldCount = this._snapshot._nodeFieldCount;
  3160. return this._snapshot._dominatorsTree[this.nodeIndex / this._snapshot._nodeFieldCount] * nodeFieldCount;
  3161. },
  3162.  
  3163. edges: function()
  3164. {
  3165. return new WebInspector.HeapSnapshotEdgeIterator(new WebInspector.HeapSnapshotEdge(this._snapshot, this.rawEdges()));
  3166. },
  3167.  
  3168. edgesCount: function()
  3169. {
  3170. return (this._edgeIndexesEnd() - this._edgeIndexesStart()) / this._snapshot._edgeFieldsCount;
  3171. },
  3172.  
  3173. flags: function()
  3174. {
  3175. return this._snapshot._flagsOfNode(this);
  3176. },
  3177.  
  3178. id: function()
  3179. {
  3180. var snapshot = this._snapshot;
  3181. return snapshot._nodes[this.nodeIndex + snapshot._nodeIdOffset];
  3182. },
  3183.  
  3184. isHidden: function()
  3185. {
  3186. return this._type() === this._snapshot._nodeHiddenType;
  3187. },
  3188.  
  3189. isNative: function()
  3190. {
  3191. return this._type() === this._snapshot._nodeNativeType;
  3192. },
  3193.  
  3194. isSynthetic: function()
  3195. {
  3196. return this._type() === this._snapshot._nodeSyntheticType;
  3197. },
  3198.  
  3199. isWindow: function()
  3200. {
  3201. const windowRE = /^Window/;
  3202. return windowRE.test(this.name());
  3203. },
  3204.  
  3205. isDetachedDOMTreesRoot: function()
  3206. {
  3207. return this.name() === "(Detached DOM trees)";
  3208. },
  3209.  
  3210. isDetachedDOMTree: function()
  3211. {
  3212. const detachedDOMTreeRE = /^Detached DOM tree/;
  3213. return detachedDOMTreeRE.test(this.className());
  3214. },
  3215.  
  3216. isRoot: function()
  3217. {
  3218. return this.nodeIndex === this._snapshot._rootNodeIndex;
  3219. },
  3220.  
  3221. name: function()
  3222. {
  3223. return this._snapshot._strings[this._name()];
  3224. },
  3225.  
  3226. rawEdges: function()
  3227. {
  3228. return new WebInspector.HeapSnapshotArraySlice(this._snapshot._containmentEdges, this._edgeIndexesStart(), this._edgeIndexesEnd());
  3229. },
  3230.  
  3231. retainedSize: function()
  3232. {
  3233. var snapshot = this._snapshot;
  3234. return snapshot._nodes[this.nodeIndex + snapshot._nodeRetainedSizeOffset];
  3235. },
  3236.  
  3237. retainers: function()
  3238. {
  3239. return new WebInspector.HeapSnapshotRetainerEdgeIterator(new WebInspector.HeapSnapshotRetainerEdge(this._snapshot, this.nodeIndex, 0));
  3240. },
  3241.  
  3242. selfSize: function()
  3243. {
  3244. var snapshot = this._snapshot;
  3245. return snapshot._nodes[this.nodeIndex + snapshot._nodeSelfSizeOffset];
  3246. },
  3247.  
  3248. type: function()
  3249. {
  3250. return this._snapshot._nodeTypes[this._type()];
  3251. },
  3252.  
  3253. _name: function()
  3254. {
  3255. var snapshot = this._snapshot;
  3256. return snapshot._nodes[this.nodeIndex + snapshot._nodeNameOffset];
  3257. },
  3258.  
  3259. _edgeIndexesStart: function()
  3260. {
  3261. return this._snapshot._firstEdgeIndexes[this._ordinal()];
  3262. },
  3263.  
  3264. _edgeIndexesEnd: function()
  3265. {
  3266. return this._snapshot._firstEdgeIndexes[this._ordinal() + 1];
  3267. },
  3268.  
  3269. _ordinal: function()
  3270. {
  3271. return this.nodeIndex / this._snapshot._nodeFieldCount;
  3272. },
  3273.  
  3274. _nextNodeIndex: function()
  3275. {
  3276. return this.nodeIndex + this._snapshot._nodeFieldCount;
  3277. },
  3278.  
  3279. _type: function()
  3280. {
  3281. var snapshot = this._snapshot;
  3282. return snapshot._nodes[this.nodeIndex + snapshot._nodeTypeOffset];
  3283. }
  3284. };
  3285.  
  3286.  
  3287. WebInspector.HeapSnapshotNodeIterator = function(node)
  3288. {
  3289. this.node = node;
  3290. this._nodesLength = node._snapshot._nodes.length;
  3291. }
  3292.  
  3293. WebInspector.HeapSnapshotNodeIterator.prototype = {
  3294. first: function()
  3295. {
  3296. this.node.nodeIndex = this.node._firstNodeIndex;
  3297. },
  3298.  
  3299. hasNext: function()
  3300. {
  3301. return this.node.nodeIndex < this._nodesLength;
  3302. },
  3303.  
  3304. index: function()
  3305. {
  3306. return this.node.nodeIndex;
  3307. },
  3308.  
  3309. setIndex: function(newIndex)
  3310. {
  3311. this.node.nodeIndex = newIndex;
  3312. },
  3313.  
  3314. item: function()
  3315. {
  3316. return this.node;
  3317. },
  3318.  
  3319. next: function()
  3320. {
  3321. this.node.nodeIndex = this.node._nextNodeIndex();
  3322. }
  3323. }
  3324.  
  3325.  
  3326. WebInspector.HeapSnapshot = function(profile)
  3327. {
  3328. this.uid = profile.snapshot.uid;
  3329. this._nodes = profile.nodes;
  3330. this._containmentEdges = profile.edges;
  3331.  
  3332. this._metaNode = profile.snapshot.meta;
  3333. this._strings = profile.strings;
  3334.  
  3335. this._snapshotDiffs = {};
  3336. this._aggregatesForDiff = null;
  3337.  
  3338. this._init();
  3339. }
  3340.  
  3341.  
  3342. function HeapSnapshotMetainfo()
  3343. {
  3344.  
  3345. this.node_fields = [];
  3346. this.node_types = [];
  3347. this.edge_fields = [];
  3348. this.edge_types = [];
  3349.  
  3350.  
  3351. this.fields = [];
  3352. this.types = [];
  3353. }
  3354.  
  3355.  
  3356. function HeapSnapshotHeader()
  3357. {
  3358.  
  3359. this.title = "";
  3360. this.uid = 0;
  3361. this.meta = new HeapSnapshotMetainfo();
  3362. this.node_count = 0;
  3363. this.edge_count = 0;
  3364. }
  3365.  
  3366. WebInspector.HeapSnapshot.prototype = {
  3367. _init: function()
  3368. {
  3369. var meta = this._metaNode;
  3370. this._rootNodeIndex = 0;
  3371.  
  3372. this._nodeTypeOffset = meta.node_fields.indexOf("type");
  3373. this._nodeNameOffset = meta.node_fields.indexOf("name");
  3374. this._nodeIdOffset = meta.node_fields.indexOf("id");
  3375. this._nodeSelfSizeOffset = meta.node_fields.indexOf("self_size");
  3376. this._nodeEdgeCountOffset = meta.node_fields.indexOf("edge_count");
  3377. this._nodeFieldCount = meta.node_fields.length;
  3378.  
  3379. this._nodeTypes = meta.node_types[this._nodeTypeOffset];
  3380. this._nodeHiddenType = this._nodeTypes.indexOf("hidden");
  3381. this._nodeObjectType = this._nodeTypes.indexOf("object");
  3382. this._nodeNativeType = this._nodeTypes.indexOf("native");
  3383. this._nodeCodeType = this._nodeTypes.indexOf("code");
  3384. this._nodeSyntheticType = this._nodeTypes.indexOf("synthetic");
  3385.  
  3386. this._edgeFieldsCount = meta.edge_fields.length;
  3387. this._edgeTypeOffset = meta.edge_fields.indexOf("type");
  3388. this._edgeNameOffset = meta.edge_fields.indexOf("name_or_index");
  3389. this._edgeToNodeOffset = meta.edge_fields.indexOf("to_node");
  3390.  
  3391. this._edgeTypes = meta.edge_types[this._edgeTypeOffset];
  3392. this._edgeTypes.push("invisible");
  3393. this._edgeElementType = this._edgeTypes.indexOf("element");
  3394. this._edgeHiddenType = this._edgeTypes.indexOf("hidden");
  3395. this._edgeInternalType = this._edgeTypes.indexOf("internal");
  3396. this._edgeShortcutType = this._edgeTypes.indexOf("shortcut");
  3397. this._edgeWeakType = this._edgeTypes.indexOf("weak");
  3398. this._edgeInvisibleType = this._edgeTypes.indexOf("invisible");
  3399.  
  3400. this._nodeFlags = { 
  3401. canBeQueried: 1,
  3402. detachedDOMTreeNode: 2,
  3403. pageObject: 4, 
  3404.  
  3405. visitedMarkerMask: 0x0ffff, 
  3406. visitedMarker:     0x10000  
  3407. };
  3408.  
  3409. this.nodeCount = this._nodes.length / this._nodeFieldCount;
  3410. this._edgeCount = this._containmentEdges.length / this._edgeFieldsCount;
  3411.  
  3412. this._buildEdgeIndexes();
  3413. this._markInvisibleEdges();
  3414. this._buildRetainers();
  3415. this._calculateFlags();
  3416. this._calculateObjectToWindowDistance();
  3417. var result = this._buildPostOrderIndex();
  3418.  
  3419. this._dominatorsTree = this._buildDominatorTree(result.postOrderIndex2NodeOrdinal, result.nodeOrdinal2PostOrderIndex);
  3420. this._calculateRetainedSizes(result.postOrderIndex2NodeOrdinal);
  3421. this._buildDominatedNodes();
  3422. },
  3423.  
  3424. _buildEdgeIndexes: function()
  3425. {
  3426.  
  3427. if (this._nodeEdgeCountOffset === -1) {
  3428. var nodes = this._nodes;
  3429. var nodeCount = this.nodeCount;
  3430. var firstEdgeIndexes = this._firstEdgeIndexes = new Uint32Array(nodeCount + 1);
  3431. var nodeFieldCount = this._nodeFieldCount;
  3432. var nodeEdgesIndexOffset = this._metaNode.node_fields.indexOf("edges_index");
  3433. firstEdgeIndexes[nodeCount] = this._containmentEdges.length;
  3434. for (var nodeOrdinal = 0; nodeOrdinal < nodeCount; ++nodeOrdinal) {
  3435. firstEdgeIndexes[nodeOrdinal] = nodes[nodeOrdinal * nodeFieldCount + nodeEdgesIndexOffset];
  3436. }
  3437. return;
  3438. }
  3439.  
  3440. var nodes = this._nodes;
  3441. var nodeCount = this.nodeCount;
  3442. var firstEdgeIndexes = this._firstEdgeIndexes = new Uint32Array(nodeCount + 1);
  3443. var nodeFieldCount = this._nodeFieldCount;
  3444. var edgeFieldsCount = this._edgeFieldsCount;
  3445. var nodeEdgeCountOffset = this._nodeEdgeCountOffset;
  3446. firstEdgeIndexes[nodeCount] = this._containmentEdges.length;
  3447. for (var nodeOrdinal = 0, edgeIndex = 0; nodeOrdinal < nodeCount; ++nodeOrdinal) {
  3448. firstEdgeIndexes[nodeOrdinal] = edgeIndex;
  3449. edgeIndex += nodes[nodeOrdinal * nodeFieldCount + nodeEdgeCountOffset] * edgeFieldsCount;
  3450. }
  3451. },
  3452.  
  3453. _buildRetainers: function()
  3454. {
  3455. var retainingNodes = this._retainingNodes = new Uint32Array(this._edgeCount);
  3456. var retainingEdges = this._retainingEdges = new Uint32Array(this._edgeCount);
  3457.  
  3458.  
  3459. var firstRetainerIndex = this._firstRetainerIndex = new Uint32Array(this.nodeCount + 1);
  3460.  
  3461. var containmentEdges = this._containmentEdges;
  3462. var edgeFieldsCount = this._edgeFieldsCount;
  3463. var nodeFieldCount = this._nodeFieldCount;
  3464. var edgeToNodeOffset = this._edgeToNodeOffset;
  3465. var nodes = this._nodes;
  3466. var firstEdgeIndexes = this._firstEdgeIndexes;
  3467. var nodeCount = this.nodeCount;
  3468.  
  3469. for (var toNodeFieldIndex = edgeToNodeOffset, l = containmentEdges.length; toNodeFieldIndex < l; toNodeFieldIndex += edgeFieldsCount) {
  3470. var toNodeIndex = containmentEdges[toNodeFieldIndex];
  3471. if (toNodeIndex % nodeFieldCount)
  3472. throw new Error("Invalid toNodeIndex " + toNodeIndex);
  3473. ++firstRetainerIndex[toNodeIndex / nodeFieldCount];
  3474. }
  3475. for (var i = 0, firstUnusedRetainerSlot = 0; i < nodeCount; i++) {
  3476. var retainersCount = firstRetainerIndex[i];
  3477. firstRetainerIndex[i] = firstUnusedRetainerSlot;
  3478. retainingNodes[firstUnusedRetainerSlot] = retainersCount;
  3479. firstUnusedRetainerSlot += retainersCount;
  3480. }
  3481. firstRetainerIndex[nodeCount] = retainingNodes.length;
  3482.  
  3483. var nextNodeFirstEdgeIndex = firstEdgeIndexes[0];
  3484. for (var srcNodeOrdinal = 0; srcNodeOrdinal < nodeCount; ++srcNodeOrdinal) {
  3485. var firstEdgeIndex = nextNodeFirstEdgeIndex;
  3486. nextNodeFirstEdgeIndex = firstEdgeIndexes[srcNodeOrdinal + 1];
  3487. var srcNodeIndex = srcNodeOrdinal * nodeFieldCount;
  3488. for (var edgeIndex = firstEdgeIndex; edgeIndex < nextNodeFirstEdgeIndex; edgeIndex += edgeFieldsCount) {
  3489. var toNodeIndex = containmentEdges[edgeIndex + edgeToNodeOffset];
  3490. if (toNodeIndex % nodeFieldCount)
  3491. throw new Error("Invalid toNodeIndex " + toNodeIndex);
  3492. var firstRetainerSlotIndex = firstRetainerIndex[toNodeIndex / nodeFieldCount];
  3493. var nextUnusedRetainerSlotIndex = firstRetainerSlotIndex + (--retainingNodes[firstRetainerSlotIndex]);
  3494. retainingNodes[nextUnusedRetainerSlotIndex] = srcNodeIndex;
  3495. retainingEdges[nextUnusedRetainerSlotIndex] = edgeIndex;
  3496. }
  3497. }
  3498. },
  3499.  
  3500. dispose: function()
  3501. {
  3502. delete this._nodes;
  3503. delete this._strings;
  3504. delete this._retainingEdges;
  3505. delete this._retainingNodes;
  3506. delete this._firstRetainerIndex;
  3507. if (this._aggregates) {
  3508. delete this._aggregates;
  3509. delete this._aggregatesSortedFlags;
  3510. }
  3511. delete this._dominatedNodes;
  3512. delete this._firstDominatedNodeIndex;
  3513. delete this._flags;
  3514. delete this._distancesToWindow;
  3515. delete this._dominatorsTree;
  3516. },
  3517.  
  3518. _allNodes: function()
  3519. {
  3520. return new WebInspector.HeapSnapshotNodeIterator(this.rootNode());
  3521. },
  3522.  
  3523. rootNode: function()
  3524. {
  3525. return new WebInspector.HeapSnapshotNode(this, this._rootNodeIndex);
  3526. },
  3527.  
  3528. get rootNodeIndex()
  3529. {
  3530. return this._rootNodeIndex;
  3531. },
  3532.  
  3533. get totalSize()
  3534. {
  3535. return this.rootNode().retainedSize();
  3536. },
  3537.  
  3538. _getDominatedIndex: function(nodeIndex)
  3539. {
  3540. if (nodeIndex % this._nodeFieldCount)
  3541. throw new Error("Invalid nodeIndex: " + nodeIndex);
  3542. return this._firstDominatedNodeIndex[nodeIndex / this._nodeFieldCount];
  3543. },
  3544.  
  3545. _dominatedNodesOfNode: function(node)
  3546. {
  3547. var dominatedIndexFrom = this._getDominatedIndex(node.nodeIndex);
  3548. var dominatedIndexTo = this._getDominatedIndex(node._nextNodeIndex());
  3549. return new WebInspector.HeapSnapshotArraySlice(this._dominatedNodes, dominatedIndexFrom, dominatedIndexTo);
  3550. },
  3551.  
  3552. _flagsOfNode: function(node)
  3553. {
  3554. return this._flags[node.nodeIndex / this._nodeFieldCount];
  3555. },
  3556.  
  3557.  
  3558. aggregates: function(sortedIndexes, key, filterString)
  3559. {
  3560. if (!this._aggregates) {
  3561. this._aggregates = {};
  3562. this._aggregatesSortedFlags = {};
  3563. }
  3564.  
  3565. var aggregatesByClassName = this._aggregates[key];
  3566. if (aggregatesByClassName) {
  3567. if (sortedIndexes && !this._aggregatesSortedFlags[key]) {
  3568. this._sortAggregateIndexes(aggregatesByClassName);
  3569. this._aggregatesSortedFlags[key] = sortedIndexes;
  3570. }
  3571. return aggregatesByClassName;
  3572. }
  3573.  
  3574. var filter;
  3575. if (filterString)
  3576. filter = this._parseFilter(filterString);
  3577.  
  3578. var aggregates = this._buildAggregates(filter);
  3579. this._calculateClassesRetainedSize(aggregates.aggregatesByClassIndex, filter);
  3580. aggregatesByClassName = aggregates.aggregatesByClassName;
  3581.  
  3582. if (sortedIndexes)
  3583. this._sortAggregateIndexes(aggregatesByClassName);
  3584.  
  3585. this._aggregatesSortedFlags[key] = sortedIndexes;
  3586. this._aggregates[key] = aggregatesByClassName;
  3587.  
  3588. return aggregatesByClassName;
  3589. },
  3590.  
  3591. aggregatesForDiff: function()
  3592. {
  3593. if (this._aggregatesForDiff)
  3594. return this._aggregatesForDiff;
  3595.  
  3596. var aggregatesByClassName = this.aggregates(true, "allObjects");
  3597. this._aggregatesForDiff  = {};
  3598.  
  3599. var node = new WebInspector.HeapSnapshotNode(this);
  3600. for (var className in aggregatesByClassName) {
  3601. var aggregate = aggregatesByClassName[className];
  3602. var indexes = aggregate.idxs;
  3603. var ids = new Array(indexes.length);
  3604. var selfSizes = new Array(indexes.length);
  3605. for (var i = 0; i < indexes.length; i++) {
  3606. node.nodeIndex = indexes[i];
  3607. ids[i] = node.id();
  3608. selfSizes[i] = node.selfSize();
  3609. }
  3610.  
  3611. this._aggregatesForDiff[className] = {
  3612. indexes: indexes,
  3613. ids: ids,
  3614. selfSizes: selfSizes
  3615. };
  3616. }
  3617. return this._aggregatesForDiff;
  3618. },
  3619.  
  3620. _calculateObjectToWindowDistance: function()
  3621. {
  3622. var nodeFieldCount = this._nodeFieldCount;
  3623. var distances = new Uint32Array(this.nodeCount);
  3624.  
  3625.  
  3626. var nodesToVisit = new Uint32Array(this.nodeCount);
  3627. var nodesToVisitLength = 0;
  3628. for (var iter = this.rootNode().edges(); iter.hasNext(); iter.next()) {
  3629. var node = iter.edge.node();
  3630. if (node.isWindow()) {
  3631. nodesToVisit[nodesToVisitLength++] = node.nodeIndex;
  3632. distances[node.nodeIndex / nodeFieldCount] = 1;
  3633. }
  3634. }
  3635. this._bfs(nodesToVisit, nodesToVisitLength, distances);
  3636.  
  3637.  
  3638. nodesToVisitLength = 0;
  3639. nodesToVisit[nodesToVisitLength++] = this._rootNodeIndex;
  3640. distances[this._rootNodeIndex / nodeFieldCount] = 1;
  3641. this._bfs(nodesToVisit, nodesToVisitLength, distances);
  3642. this._distancesToWindow = distances;
  3643. },
  3644.  
  3645. _bfs: function(nodesToVisit, nodesToVisitLength, distances)
  3646. {
  3647.  
  3648. var edgeFieldsCount = this._edgeFieldsCount;
  3649. var nodeFieldCount = this._nodeFieldCount;
  3650. var containmentEdges = this._containmentEdges;
  3651. var firstEdgeIndexes = this._firstEdgeIndexes;
  3652. var edgeToNodeOffset = this._edgeToNodeOffset;
  3653. var edgeTypeOffset = this._edgeTypeOffset;
  3654. var nodes = this._nodes;
  3655. var nodeCount = this.nodeCount;
  3656. var containmentEdgesLength = containmentEdges.length;
  3657. var edgeWeakType = this._edgeWeakType;
  3658. var edgeShortcutType = this._edgeShortcutType;
  3659.  
  3660. var index = 0;
  3661. while (index < nodesToVisitLength) {
  3662. var nodeIndex = nodesToVisit[index++]; 
  3663. var nodeOrdinal = nodeIndex / nodeFieldCount;
  3664. var distance = distances[nodeOrdinal] + 1;
  3665. var firstEdgeIndex = firstEdgeIndexes[nodeOrdinal];
  3666. var edgesEnd = firstEdgeIndexes[nodeOrdinal + 1];
  3667. for (var edgeIndex = firstEdgeIndex; edgeIndex < edgesEnd; edgeIndex += edgeFieldsCount) {
  3668. var edgeType = containmentEdges[edgeIndex + edgeTypeOffset];
  3669. if (edgeType == edgeWeakType)
  3670. continue;
  3671. var childNodeIndex = containmentEdges[edgeIndex + edgeToNodeOffset];
  3672. var childNodeOrdinal = childNodeIndex / nodeFieldCount;
  3673. if (distances[childNodeOrdinal])
  3674. continue;
  3675. distances[childNodeOrdinal] = distance;
  3676. nodesToVisit[nodesToVisitLength++] = childNodeIndex;
  3677. }
  3678. }
  3679. if (nodesToVisitLength > nodeCount)
  3680. throw new Error("BFS failed. Nodes to visit (" + nodesToVisitLength + ") is more than nodes count (" + nodeCount + ")");
  3681. },
  3682.  
  3683. _buildAggregates: function(filter)
  3684. {
  3685. var aggregates = {};
  3686. var aggregatesByClassName = {};
  3687. var classIndexes = [];
  3688. var nodes = this._nodes;
  3689. var flags = this._flags;
  3690. var nodesLength = nodes.length;
  3691. var nodeNativeType = this._nodeNativeType;
  3692. var nodeFieldCount = this._nodeFieldCount;
  3693. var selfSizeOffset = this._nodeSelfSizeOffset;
  3694. var nodeTypeOffset = this._nodeTypeOffset;
  3695. var pageObjectFlag = this._nodeFlags.pageObject;
  3696. var node = new WebInspector.HeapSnapshotNode(this, this._rootNodeIndex);
  3697. var distancesToWindow = this._distancesToWindow;
  3698.  
  3699. for (var nodeIndex = this._rootNodeIndex; nodeIndex < nodesLength; nodeIndex += nodeFieldCount) {
  3700. var nodeOrdinal = nodeIndex / nodeFieldCount;
  3701. if (!(flags[nodeOrdinal] & pageObjectFlag))
  3702. continue;
  3703. node.nodeIndex = nodeIndex;
  3704. if (filter && !filter(node))
  3705. continue;
  3706. var selfSize = nodes[nodeIndex + selfSizeOffset];
  3707. if (!selfSize && nodes[nodeIndex + nodeTypeOffset] !== nodeNativeType)
  3708. continue;
  3709. var classIndex = node.classIndex();
  3710. if (!(classIndex in aggregates)) {
  3711. var nodeType = node.type();
  3712. var nameMatters = nodeType === "object" || nodeType === "native";
  3713. var value = {
  3714. count: 1,
  3715. distanceToWindow: distancesToWindow[nodeOrdinal],
  3716. self: selfSize,
  3717. maxRet: 0,
  3718. type: nodeType,
  3719. name: nameMatters ? node.name() : null,
  3720. idxs: [nodeIndex]
  3721. };
  3722. aggregates[classIndex] = value;
  3723. classIndexes.push(classIndex);
  3724. aggregatesByClassName[node.className()] = value;
  3725. } else {
  3726. var clss = aggregates[classIndex];
  3727. clss.distanceToWindow = Math.min(clss.distanceToWindow, distancesToWindow[nodeOrdinal]);
  3728. ++clss.count;
  3729. clss.self += selfSize;
  3730. clss.idxs.push(nodeIndex);
  3731. }
  3732. }
  3733.  
  3734.  
  3735. for (var i = 0, l = classIndexes.length; i < l; ++i) {
  3736. var classIndex = classIndexes[i];
  3737. aggregates[classIndex].idxs = aggregates[classIndex].idxs.slice();
  3738. }
  3739. return {aggregatesByClassName: aggregatesByClassName, aggregatesByClassIndex: aggregates};
  3740. },
  3741.  
  3742. _calculateClassesRetainedSize: function(aggregates, filter)
  3743. {
  3744. var rootNodeIndex = this._rootNodeIndex;
  3745. var node = new WebInspector.HeapSnapshotNode(this, rootNodeIndex);
  3746. var list = [rootNodeIndex];
  3747. var sizes = [-1];
  3748. var classes = [];
  3749. var seenClassNameIndexes = {};
  3750. var nodeFieldCount = this._nodeFieldCount;
  3751. var nodeTypeOffset = this._nodeTypeOffset;
  3752. var nodeNativeType = this._nodeNativeType;
  3753. var dominatedNodes = this._dominatedNodes;
  3754. var nodes = this._nodes;
  3755. var flags = this._flags;
  3756. var pageObjectFlag = this._nodeFlags.pageObject;
  3757. var firstDominatedNodeIndex = this._firstDominatedNodeIndex;
  3758.  
  3759. while (list.length) {
  3760. var nodeIndex = list.pop();
  3761. node.nodeIndex = nodeIndex;
  3762. var classIndex = node.classIndex();
  3763. var seen = !!seenClassNameIndexes[classIndex];
  3764. var nodeOrdinal = nodeIndex / nodeFieldCount;
  3765. var dominatedIndexFrom = firstDominatedNodeIndex[nodeOrdinal];
  3766. var dominatedIndexTo = firstDominatedNodeIndex[nodeOrdinal + 1];
  3767.  
  3768. if (!seen &&
  3769. (flags[nodeOrdinal] & pageObjectFlag) &&
  3770. (!filter || filter(node)) &&
  3771. (node.selfSize() || nodes[nodeIndex + nodeTypeOffset] === nodeNativeType)
  3772. ) {
  3773. aggregates[classIndex].maxRet += node.retainedSize();
  3774. if (dominatedIndexFrom !== dominatedIndexTo) {
  3775. seenClassNameIndexes[classIndex] = true;
  3776. sizes.push(list.length);
  3777. classes.push(classIndex);
  3778. }
  3779. }
  3780. for (var i = dominatedIndexFrom; i < dominatedIndexTo; i++)
  3781. list.push(dominatedNodes[i]);
  3782.  
  3783. var l = list.length;
  3784. while (sizes[sizes.length - 1] === l) {
  3785. sizes.pop();
  3786. classIndex = classes.pop();
  3787. seenClassNameIndexes[classIndex] = false;
  3788. }
  3789. }
  3790. },
  3791.  
  3792. _sortAggregateIndexes: function(aggregates)
  3793. {
  3794. var nodeA = new WebInspector.HeapSnapshotNode(this);
  3795. var nodeB = new WebInspector.HeapSnapshotNode(this);
  3796. for (var clss in aggregates)
  3797. aggregates[clss].idxs.sort(
  3798. function(idxA, idxB) {
  3799. nodeA.nodeIndex = idxA;
  3800. nodeB.nodeIndex = idxB;
  3801. return nodeA.id() < nodeB.id() ? -1 : 1;
  3802. });
  3803. },
  3804.  
  3805. _buildPostOrderIndex: function()
  3806. {
  3807. var nodeFieldCount = this._nodeFieldCount;
  3808. var nodes = this._nodes;
  3809. var nodeCount = this.nodeCount;
  3810. var rootNodeOrdinal = this._rootNodeIndex / nodeFieldCount;
  3811.  
  3812. var edgeFieldsCount = this._edgeFieldsCount;
  3813. var edgeTypeOffset = this._edgeTypeOffset;
  3814. var edgeToNodeOffset = this._edgeToNodeOffset;
  3815. var edgeShortcutType = this._edgeShortcutType;
  3816. var firstEdgeIndexes = this._firstEdgeIndexes;
  3817. var containmentEdges = this._containmentEdges;
  3818. var containmentEdgesLength = this._containmentEdges.length;
  3819.  
  3820. var flags = this._flags;
  3821. var flag = this._nodeFlags.pageObject;
  3822.  
  3823. var nodesToVisit = new Uint32Array(nodeCount);
  3824. var postOrderIndex2NodeOrdinal = new Uint32Array(nodeCount);
  3825. var nodeOrdinal2PostOrderIndex = new Uint32Array(nodeCount);
  3826. var painted = new Uint8Array(nodeCount);
  3827. var nodesToVisitLength = 0;
  3828. var postOrderIndex = 0;
  3829. var grey = 1;
  3830. var black = 2;
  3831.  
  3832. nodesToVisit[nodesToVisitLength++] = rootNodeOrdinal;
  3833. painted[rootNodeOrdinal] = grey;
  3834.  
  3835. while (nodesToVisitLength) {
  3836. var nodeOrdinal = nodesToVisit[nodesToVisitLength - 1];
  3837. if (painted[nodeOrdinal] === grey) {
  3838. painted[nodeOrdinal] = black;
  3839. var nodeFlag = flags[nodeOrdinal] & flag;
  3840. var beginEdgeIndex = firstEdgeIndexes[nodeOrdinal];
  3841. var endEdgeIndex = firstEdgeIndexes[nodeOrdinal + 1];
  3842. for (var edgeIndex = beginEdgeIndex; edgeIndex < endEdgeIndex; edgeIndex += edgeFieldsCount) {
  3843. if (nodeOrdinal !== rootNodeOrdinal && containmentEdges[edgeIndex + edgeTypeOffset] === edgeShortcutType)
  3844. continue;
  3845. var childNodeIndex = containmentEdges[edgeIndex + edgeToNodeOffset];
  3846. var childNodeOrdinal = childNodeIndex / nodeFieldCount;
  3847. var childNodeFlag = flags[childNodeOrdinal] & flag;
  3848.  
  3849.  
  3850. if (nodeOrdinal !== rootNodeOrdinal && childNodeFlag && !nodeFlag)
  3851. continue;
  3852. if (!painted[childNodeOrdinal]) {
  3853. painted[childNodeOrdinal] = grey;
  3854. nodesToVisit[nodesToVisitLength++] = childNodeOrdinal;
  3855. }
  3856. }
  3857. } else {
  3858. nodeOrdinal2PostOrderIndex[nodeOrdinal] = postOrderIndex;
  3859. postOrderIndex2NodeOrdinal[postOrderIndex++] = nodeOrdinal;
  3860. --nodesToVisitLength;
  3861. }
  3862. }
  3863.  
  3864. if (postOrderIndex !== nodeCount)
  3865. throw new Error("Postordering failed. " + (nodeCount - postOrderIndex) + " hanging nodes");
  3866.  
  3867. return {postOrderIndex2NodeOrdinal: postOrderIndex2NodeOrdinal, nodeOrdinal2PostOrderIndex: nodeOrdinal2PostOrderIndex};
  3868. },
  3869.  
  3870.  
  3871.  
  3872.  
  3873.  
  3874. _buildDominatorTree: function(postOrderIndex2NodeOrdinal, nodeOrdinal2PostOrderIndex)
  3875. {
  3876. var nodeFieldCount = this._nodeFieldCount;
  3877. var nodes = this._nodes;
  3878. var firstRetainerIndex = this._firstRetainerIndex;
  3879. var retainingNodes = this._retainingNodes;
  3880. var retainingEdges = this._retainingEdges;
  3881. var edgeFieldsCount = this._edgeFieldsCount;
  3882. var edgeTypeOffset = this._edgeTypeOffset;
  3883. var edgeToNodeOffset = this._edgeToNodeOffset;
  3884. var edgeShortcutType = this._edgeShortcutType;
  3885. var firstEdgeIndexes = this._firstEdgeIndexes;
  3886. var containmentEdges = this._containmentEdges;
  3887. var containmentEdgesLength = this._containmentEdges.length;
  3888. var rootNodeIndex = this._rootNodeIndex;
  3889.  
  3890. var flags = this._flags;
  3891. var flag = this._nodeFlags.pageObject;
  3892.  
  3893. var nodesCount = postOrderIndex2NodeOrdinal.length;
  3894. var rootPostOrderedIndex = nodesCount - 1;
  3895. var noEntry = nodesCount;
  3896. var dominators = new Uint32Array(nodesCount);
  3897. for (var i = 0; i < rootPostOrderedIndex; ++i)
  3898. dominators[i] = noEntry;
  3899. dominators[rootPostOrderedIndex] = rootPostOrderedIndex;
  3900.  
  3901.  
  3902.  
  3903. var affected = new Uint8Array(nodesCount);
  3904. var nodeOrdinal;
  3905.  
  3906. nodeOrdinal = this._rootNodeIndex / nodeFieldCount;
  3907. var beginEdgeToNodeFieldIndex = firstEdgeIndexes[nodeOrdinal] + edgeToNodeOffset;
  3908. var endEdgeToNodeFieldIndex = firstEdgeIndexes[nodeOrdinal + 1];
  3909. for (var toNodeFieldIndex = beginEdgeToNodeFieldIndex;
  3910. toNodeFieldIndex < endEdgeToNodeFieldIndex;
  3911. toNodeFieldIndex += edgeFieldsCount) {
  3912. var childNodeOrdinal = containmentEdges[toNodeFieldIndex] / nodeFieldCount;
  3913. affected[nodeOrdinal2PostOrderIndex[childNodeOrdinal]] = 1;
  3914. }
  3915. }
  3916.  
  3917. var changed = true;
  3918. while (changed) {
  3919. changed = false;
  3920. for (var postOrderIndex = rootPostOrderedIndex - 1; postOrderIndex >= 0; --postOrderIndex) {
  3921. if (affected[postOrderIndex] === 0)
  3922. continue;
  3923. affected[postOrderIndex] = 0;
  3924.  
  3925.  
  3926. if (dominators[postOrderIndex] === rootPostOrderedIndex)
  3927. continue;
  3928. nodeOrdinal = postOrderIndex2NodeOrdinal[postOrderIndex];
  3929. var nodeFlag = !!(flags[nodeOrdinal] & flag);
  3930. var newDominatorIndex = noEntry;
  3931. var beginRetainerIndex = firstRetainerIndex[nodeOrdinal];
  3932. var endRetainerIndex = firstRetainerIndex[nodeOrdinal + 1];
  3933. for (var retainerIndex = beginRetainerIndex; retainerIndex < endRetainerIndex; ++retainerIndex) {
  3934. var retainerEdgeIndex = retainingEdges[retainerIndex];
  3935. var retainerEdgeType = containmentEdges[retainerEdgeIndex + edgeTypeOffset];
  3936. var retainerNodeIndex = retainingNodes[retainerIndex];
  3937. if (retainerNodeIndex !== rootNodeIndex && retainerEdgeType === edgeShortcutType)
  3938. continue;
  3939. var retainerNodeOrdinal = retainerNodeIndex / nodeFieldCount;
  3940. var retainerNodeFlag = !!(flags[retainerNodeOrdinal] & flag);
  3941.  
  3942.  
  3943. if (retainerNodeIndex !== rootNodeIndex && nodeFlag && !retainerNodeFlag)
  3944. continue;
  3945. var retanerPostOrderIndex = nodeOrdinal2PostOrderIndex[retainerNodeOrdinal];
  3946. if (dominators[retanerPostOrderIndex] !== noEntry) {
  3947. if (newDominatorIndex === noEntry)
  3948. newDominatorIndex = retanerPostOrderIndex;
  3949. else {
  3950. while (retanerPostOrderIndex !== newDominatorIndex) {
  3951. while (retanerPostOrderIndex < newDominatorIndex)
  3952. retanerPostOrderIndex = dominators[retanerPostOrderIndex];
  3953. while (newDominatorIndex < retanerPostOrderIndex)
  3954. newDominatorIndex = dominators[newDominatorIndex];
  3955. }
  3956. }
  3957.  
  3958.  
  3959. if (newDominatorIndex === rootPostOrderedIndex)
  3960. break;
  3961. }
  3962. }
  3963. if (newDominatorIndex !== noEntry && dominators[postOrderIndex] !== newDominatorIndex) {
  3964. dominators[postOrderIndex] = newDominatorIndex;
  3965. changed = true;
  3966. nodeOrdinal = postOrderIndex2NodeOrdinal[postOrderIndex];
  3967. beginEdgeToNodeFieldIndex = firstEdgeIndexes[nodeOrdinal] + edgeToNodeOffset;
  3968. endEdgeToNodeFieldIndex = firstEdgeIndexes[nodeOrdinal + 1];
  3969. for (var toNodeFieldIndex = beginEdgeToNodeFieldIndex;
  3970. toNodeFieldIndex < endEdgeToNodeFieldIndex;
  3971. toNodeFieldIndex += edgeFieldsCount) {
  3972. var childNodeOrdinal = containmentEdges[toNodeFieldIndex] / nodeFieldCount;
  3973. affected[nodeOrdinal2PostOrderIndex[childNodeOrdinal]] = 1;
  3974. }
  3975. }
  3976. }
  3977. }
  3978.  
  3979. var dominatorsTree = new Uint32Array(nodesCount);
  3980. for (var postOrderIndex = 0, l = dominators.length; postOrderIndex < l; ++postOrderIndex) {
  3981. nodeOrdinal = postOrderIndex2NodeOrdinal[postOrderIndex];
  3982. dominatorsTree[nodeOrdinal] = postOrderIndex2NodeOrdinal[dominators[postOrderIndex]];
  3983. }
  3984. return dominatorsTree;
  3985. },
  3986.  
  3987. _calculateRetainedSizes: function(postOrderIndex2NodeOrdinal)
  3988. {
  3989. var nodeCount = this.nodeCount;
  3990. var nodes = this._nodes;
  3991. var nodeSelfSizeOffset = this._nodeSelfSizeOffset;
  3992. var nodeFieldCount = this._nodeFieldCount;
  3993. var dominatorsTree = this._dominatorsTree;
  3994.  
  3995. var nodeRetainedSizeOffset = this._nodeRetainedSizeOffset = this._nodeEdgeCountOffset;
  3996. delete this._nodeEdgeCountOffset;
  3997.  
  3998. for (var nodeIndex = 0, l = nodes.length; nodeIndex < l; nodeIndex += nodeFieldCount)
  3999. nodes[nodeIndex + nodeRetainedSizeOffset] = nodes[nodeIndex + nodeSelfSizeOffset];
  4000.  
  4001.  
  4002. for (var postOrderIndex = 0; postOrderIndex < nodeCount - 1; ++postOrderIndex) {
  4003. var nodeOrdinal = postOrderIndex2NodeOrdinal[postOrderIndex];
  4004. var nodeIndex = nodeOrdinal * nodeFieldCount;
  4005. var dominatorIndex = dominatorsTree[nodeOrdinal] * nodeFieldCount;
  4006. nodes[dominatorIndex + nodeRetainedSizeOffset] += nodes[nodeIndex + nodeRetainedSizeOffset];
  4007. }
  4008. },
  4009.  
  4010. _buildDominatedNodes: function()
  4011. {
  4012.  
  4013.  
  4014.  
  4015.  
  4016.  
  4017. var indexArray = this._firstDominatedNodeIndex = new Uint32Array(this.nodeCount + 1);
  4018.  
  4019. var dominatedNodes = this._dominatedNodes = new Uint32Array(this.nodeCount - 1);
  4020.  
  4021.  
  4022.  
  4023. var nodeFieldCount = this._nodeFieldCount;
  4024. var dominatorsTree = this._dominatorsTree;
  4025. for (var nodeOrdinal = 1, l = this.nodeCount; nodeOrdinal < l; ++nodeOrdinal)
  4026. ++indexArray[dominatorsTree[nodeOrdinal]];
  4027.  
  4028.  
  4029. var firstDominatedNodeIndex = 0;
  4030. for (var i = 0, l = this.nodeCount; i < l; ++i) {
  4031. var dominatedCount = dominatedNodes[firstDominatedNodeIndex] = indexArray[i];
  4032. indexArray[i] = firstDominatedNodeIndex;
  4033. firstDominatedNodeIndex += dominatedCount;
  4034. }
  4035. indexArray[this.nodeCount] = dominatedNodes.length;
  4036.  
  4037.  
  4038. for (var nodeOrdinal = 1, l = this.nodeCount; nodeOrdinal < l; ++nodeOrdinal) {
  4039. var dominatorOrdinal = dominatorsTree[nodeOrdinal];
  4040. var dominatedRefIndex = indexArray[dominatorOrdinal];
  4041. dominatedRefIndex += (--dominatedNodes[dominatedRefIndex]);
  4042. dominatedNodes[dominatedRefIndex] = nodeOrdinal * nodeFieldCount;
  4043. }
  4044. },
  4045.  
  4046. _markInvisibleEdges: function()
  4047. {
  4048.  
  4049.  
  4050.  
  4051. for (var iter = this.rootNode().edges(); iter.hasNext(); iter.next()) {
  4052. var edge = iter.edge;
  4053. if (!edge.isShortcut())
  4054. continue;
  4055. var node = edge.node();
  4056. var propNames = {};
  4057. for (var innerIter = node.edges(); innerIter.hasNext(); innerIter.next()) {
  4058. var globalObjEdge = innerIter.edge;
  4059. if (globalObjEdge.isShortcut())
  4060. propNames[globalObjEdge._nameOrIndex()] = true;
  4061. }
  4062. for (innerIter.first(); innerIter.hasNext(); innerIter.next()) {
  4063. var globalObjEdge = innerIter.edge;
  4064. if (!globalObjEdge.isShortcut()
  4065. && globalObjEdge.node().isHidden()
  4066. && globalObjEdge._hasStringName()
  4067. && (globalObjEdge._nameOrIndex() in propNames))
  4068. this._containmentEdges[globalObjEdge._edges._start + globalObjEdge.edgeIndex + this._edgeTypeOffset] = this._edgeInvisibleType;
  4069. }
  4070. }
  4071. },
  4072.  
  4073. _numbersComparator: function(a, b)
  4074. {
  4075. return a < b ? -1 : (a > b ? 1 : 0);
  4076. },
  4077.  
  4078. _markDetachedDOMTreeNodes: function()
  4079. {
  4080. var flag = this._nodeFlags.detachedDOMTreeNode;
  4081. var detachedDOMTreesRoot;
  4082. for (var iter = this.rootNode().edges(); iter.hasNext(); iter.next()) {
  4083. var node = iter.edge.node();
  4084. if (node.isDetachedDOMTreesRoot()) {
  4085. detachedDOMTreesRoot = node;
  4086. break;
  4087. }
  4088. }
  4089.  
  4090. if (!detachedDOMTreesRoot)
  4091. return;
  4092.  
  4093. for (var iter = detachedDOMTreesRoot.edges(); iter.hasNext(); iter.next()) {
  4094. var node = iter.edge.node();
  4095. if (node.isDetachedDOMTree()) {
  4096. for (var edgesIter = node.edges(); edgesIter.hasNext(); edgesIter.next())
  4097. this._flags[edgesIter.edge.node().nodeIndex / this._nodeFieldCount] |= flag;
  4098. }
  4099. }
  4100. },
  4101.  
  4102. _markPageOwnedNodes: function()
  4103. {
  4104. var edgeShortcutType = this._edgeShortcutType;
  4105. var edgeToNodeOffset = this._edgeToNodeOffset;
  4106. var edgeTypeOffset = this._edgeTypeOffset;
  4107. var edgeFieldsCount = this._edgeFieldsCount;
  4108. var edgeWeakType = this._edgeWeakType;
  4109. var firstEdgeIndexes = this._firstEdgeIndexes;
  4110. var containmentEdges = this._containmentEdges;
  4111. var containmentEdgesLength = containmentEdges.length;
  4112. var nodes = this._nodes;
  4113. var nodeFieldCount = this._nodeFieldCount;
  4114. var nodesCount = this.nodeCount;
  4115.  
  4116. var flags = this._flags;
  4117. var flag = this._nodeFlags.pageObject;
  4118. var visitedMarker = this._nodeFlags.visitedMarker;
  4119. var visitedMarkerMask = this._nodeFlags.visitedMarkerMask;
  4120. var markerAndFlag = visitedMarker | flag;
  4121.  
  4122. var nodesToVisit = new Uint32Array(nodesCount);
  4123. var nodesToVisitLength = 0;
  4124.  
  4125. var rootNodeOrdinal = this._rootNodeIndex / nodeFieldCount;
  4126. for (var edgeIndex = firstEdgeIndexes[rootNodeOrdinal], endEdgeIndex = firstEdgeIndexes[rootNodeOrdinal + 1];
  4127. edgeIndex < endEdgeIndex;
  4128. edgeIndex += edgeFieldsCount) {
  4129. if (containmentEdges[edgeIndex + edgeTypeOffset] === edgeShortcutType) {
  4130. var nodeOrdinal = containmentEdges[edgeIndex + edgeToNodeOffset] / nodeFieldCount;
  4131. nodesToVisit[nodesToVisitLength++] = nodeOrdinal;
  4132. flags[nodeOrdinal] |= visitedMarker;
  4133. }
  4134. }
  4135.  
  4136. while (nodesToVisitLength) {
  4137. var nodeOrdinal = nodesToVisit[--nodesToVisitLength];
  4138. flags[nodeOrdinal] |= flag;
  4139. flags[nodeOrdinal] &= visitedMarkerMask;
  4140. var beginEdgeIndex = firstEdgeIndexes[nodeOrdinal];
  4141. var endEdgeIndex = firstEdgeIndexes[nodeOrdinal + 1];
  4142. for (var edgeIndex = beginEdgeIndex; edgeIndex < endEdgeIndex; edgeIndex += edgeFieldsCount) {
  4143. var childNodeIndex = containmentEdges[edgeIndex + edgeToNodeOffset];
  4144. var childNodeOrdinal = childNodeIndex / nodeFieldCount;
  4145. if (flags[childNodeOrdinal] & markerAndFlag)
  4146. continue;
  4147. var type = containmentEdges[edgeIndex + edgeTypeOffset];
  4148. if (type === edgeWeakType)
  4149. continue;
  4150. nodesToVisit[nodesToVisitLength++] = childNodeOrdinal;
  4151. flags[childNodeOrdinal] |= visitedMarker;
  4152. }
  4153. }
  4154. },
  4155.  
  4156. _markQueriableHeapObjects: function()
  4157. {
  4158.  
  4159.  
  4160.  
  4161. var flag = this._nodeFlags.canBeQueried;
  4162. var hiddenEdgeType = this._edgeHiddenType;
  4163. var internalEdgeType = this._edgeInternalType;
  4164. var invisibleEdgeType = this._edgeInvisibleType;
  4165. var weakEdgeType = this._edgeWeakType;
  4166. var edgeToNodeOffset = this._edgeToNodeOffset;
  4167. var edgeTypeOffset = this._edgeTypeOffset;
  4168. var edgeFieldsCount = this._edgeFieldsCount;
  4169. var containmentEdges = this._containmentEdges;
  4170. var nodes = this._nodes;
  4171. var nodeCount = this.nodeCount;
  4172. var nodeFieldCount = this._nodeFieldCount;
  4173. var firstEdgeIndexes = this._firstEdgeIndexes;
  4174.  
  4175. var flags = this._flags;
  4176. var list = [];
  4177.  
  4178. for (var iter = this.rootNode().edges(); iter.hasNext(); iter.next()) {
  4179. if (iter.edge.node().isWindow())
  4180. list.push(iter.edge.node().nodeIndex / nodeFieldCount);
  4181. }
  4182.  
  4183. while (list.length) {
  4184. var nodeOrdinal = list.pop();
  4185. if (flags[nodeOrdinal] & flag)
  4186. continue;
  4187. flags[nodeOrdinal] |= flag;
  4188. var beginEdgeIndex = firstEdgeIndexes[nodeOrdinal];
  4189. var endEdgeIndex = firstEdgeIndexes[nodeOrdinal + 1];
  4190. for (var edgeIndex = beginEdgeIndex; edgeIndex < endEdgeIndex; edgeIndex += edgeFieldsCount) {
  4191. var childNodeIndex = containmentEdges[edgeIndex + edgeToNodeOffset];
  4192. var childNodeOrdinal = childNodeIndex / nodeFieldCount;
  4193. if (flags[childNodeOrdinal] & flag)
  4194. continue;
  4195. var type = containmentEdges[edgeIndex + edgeTypeOffset];
  4196. if (type === hiddenEdgeType || type === invisibleEdgeType || type === internalEdgeType || type === weakEdgeType)
  4197. continue;
  4198. list.push(childNodeOrdinal);
  4199. }
  4200. }
  4201. },
  4202.  
  4203. _calculateFlags: function()
  4204. {
  4205. this._flags = new Uint32Array(this.nodeCount);
  4206. this._markDetachedDOMTreeNodes();
  4207. this._markQueriableHeapObjects();
  4208. this._markPageOwnedNodes();
  4209. },
  4210.  
  4211. calculateSnapshotDiff: function(baseSnapshotId, baseSnapshotAggregates)
  4212. {
  4213. var snapshotDiff = this._snapshotDiffs[baseSnapshotId];
  4214. if (snapshotDiff)
  4215. return snapshotDiff;
  4216. snapshotDiff = {};
  4217.  
  4218. var aggregates = this.aggregates(true, "allObjects");
  4219. for (var className in baseSnapshotAggregates) {
  4220. var baseAggregate = baseSnapshotAggregates[className];
  4221. var diff = this._calculateDiffForClass(baseAggregate, aggregates[className]);
  4222. if (diff)
  4223. snapshotDiff[className] = diff;
  4224. }
  4225. var emptyBaseAggregate = { ids: [], indexes: [], selfSizes: [] };
  4226. for (var className in aggregates) {
  4227. if (className in baseSnapshotAggregates)
  4228. continue;
  4229. snapshotDiff[className] = this._calculateDiffForClass(emptyBaseAggregate, aggregates[className]);
  4230. }
  4231.  
  4232. this._snapshotDiffs[baseSnapshotId] = snapshotDiff;
  4233. return snapshotDiff;
  4234. },
  4235.  
  4236. _calculateDiffForClass: function(baseAggregate, aggregate)
  4237. {
  4238. var baseIds = baseAggregate.ids;
  4239. var baseIndexes = baseAggregate.indexes;
  4240. var baseSelfSizes = baseAggregate.selfSizes;
  4241.  
  4242. var indexes = aggregate ? aggregate.idxs : [];
  4243.  
  4244. var i = 0, l = baseIds.length;
  4245. var j = 0, m = indexes.length;
  4246. var diff = { addedCount: 0,
  4247. removedCount: 0,
  4248. addedSize: 0,
  4249. removedSize: 0,
  4250. deletedIndexes: [],
  4251. addedIndexes: [] };
  4252.  
  4253. var nodeB = new WebInspector.HeapSnapshotNode(this, indexes[j]);
  4254. while (i < l && j < m) {
  4255. var nodeAId = baseIds[i];
  4256. if (nodeAId < nodeB.id()) {
  4257. diff.deletedIndexes.push(baseIndexes[i]);
  4258. diff.removedCount++;
  4259. diff.removedSize += baseSelfSizes[i];
  4260. ++i;
  4261. } else if (nodeAId > nodeB.id()) { 
  4262. diff.addedIndexes.push(indexes[j]);
  4263. diff.addedCount++;
  4264. diff.addedSize += nodeB.selfSize();
  4265. nodeB.nodeIndex = indexes[++j];
  4266. } else { 
  4267. ++i;
  4268. nodeB.nodeIndex = indexes[++j];
  4269. }
  4270. }
  4271. while (i < l) {
  4272. diff.deletedIndexes.push(baseIndexes[i]);
  4273. diff.removedCount++;
  4274. diff.removedSize += baseSelfSizes[i];
  4275. ++i;
  4276. }
  4277. while (j < m) {
  4278. diff.addedIndexes.push(indexes[j]);
  4279. diff.addedCount++;
  4280. diff.addedSize += nodeB.selfSize();
  4281. nodeB.nodeIndex = indexes[++j];
  4282. }
  4283. diff.countDelta = diff.addedCount - diff.removedCount;
  4284. diff.sizeDelta = diff.addedSize - diff.removedSize;
  4285. if (!diff.addedCount && !diff.removedCount)
  4286. return null;
  4287. return diff;
  4288. },
  4289.  
  4290. _nodeForSnapshotObjectId: function(snapshotObjectId)
  4291. {
  4292. for (var it = this._allNodes(); it.hasNext(); it.next()) {
  4293. if (it.node.id() === snapshotObjectId)
  4294. return it.node;
  4295. }
  4296. return null;
  4297. },
  4298.  
  4299. nodeClassName: function(snapshotObjectId)
  4300. {
  4301. var node = this._nodeForSnapshotObjectId(snapshotObjectId);
  4302. if (node)
  4303. return node.className();
  4304. return null;
  4305. },
  4306.  
  4307. dominatorIdsForNode: function(snapshotObjectId)
  4308. {
  4309. var node = this._nodeForSnapshotObjectId(snapshotObjectId);
  4310. if (!node)
  4311. return null;
  4312. var result = [];
  4313. while (!node.isRoot()) {
  4314. result.push(node.id());
  4315. node.nodeIndex = node.dominatorIndex();
  4316. }
  4317. return result;
  4318. },
  4319.  
  4320. _parseFilter: function(filter)
  4321. {
  4322. if (!filter)
  4323. return null;
  4324. var parsedFilter = eval("(function(){return " + filter + "})()");
  4325. return parsedFilter.bind(this);
  4326. },
  4327.  
  4328. createEdgesProvider: function(nodeIndex, filter)
  4329. {
  4330. var node = new WebInspector.HeapSnapshotNode(this, nodeIndex);
  4331. return new WebInspector.HeapSnapshotEdgesProvider(this, this._parseFilter(filter), node.edges());
  4332. },
  4333.  
  4334. createRetainingEdgesProvider: function(nodeIndex, filter)
  4335. {
  4336. var node = new WebInspector.HeapSnapshotNode(this, nodeIndex);
  4337. return new WebInspector.HeapSnapshotEdgesProvider(this, this._parseFilter(filter), node.retainers());
  4338. },
  4339.  
  4340. createAddedNodesProvider: function(baseSnapshotId, className)
  4341. {
  4342. var snapshotDiff = this._snapshotDiffs[baseSnapshotId];
  4343. var diffForClass = snapshotDiff[className];
  4344. return new WebInspector.HeapSnapshotNodesProvider(this, null, diffForClass.addedIndexes);
  4345. },
  4346.  
  4347. createDeletedNodesProvider: function(nodeIndexes)
  4348. {
  4349. return new WebInspector.HeapSnapshotNodesProvider(this, null, nodeIndexes);
  4350. },
  4351.  
  4352. createNodesProviderForClass: function(className, aggregatesKey)
  4353. {
  4354. function filter(node) {
  4355. return node.isPageObject();
  4356. }
  4357. return new WebInspector.HeapSnapshotNodesProvider(this, filter, this.aggregates(false, aggregatesKey)[className].idxs);
  4358. },
  4359.  
  4360. createNodesProviderForDominator: function(nodeIndex)
  4361. {
  4362. var node = new WebInspector.HeapSnapshotNode(this, nodeIndex);
  4363. return new WebInspector.HeapSnapshotNodesProvider(this, null, this._dominatedNodesOfNode(node));
  4364. },
  4365.  
  4366. updateStaticData: function()
  4367. {
  4368. return {nodeCount: this.nodeCount, rootNodeIndex: this._rootNodeIndex, totalSize: this.totalSize, uid: this.uid, nodeFlags: this._nodeFlags};
  4369. }
  4370. };
  4371.  
  4372.  
  4373. WebInspector.HeapSnapshotFilteredOrderedIterator = function(iterator, filter, unfilteredIterationOrder)
  4374. {
  4375. this._filter = filter;
  4376. this._iterator = iterator;
  4377. this._unfilteredIterationOrder = unfilteredIterationOrder;
  4378. this._iterationOrder = null;
  4379. this._position = 0;
  4380. this._currentComparator = null;
  4381. this._sortedPrefixLength = 0;
  4382. }
  4383.  
  4384. WebInspector.HeapSnapshotFilteredOrderedIterator.prototype = {
  4385. _createIterationOrder: function()
  4386. {
  4387. if (this._iterationOrder)
  4388. return;
  4389. if (this._unfilteredIterationOrder && !this._filter) {
  4390. this._iterationOrder = this._unfilteredIterationOrder.slice(0);
  4391. this._unfilteredIterationOrder = null;
  4392. return;
  4393. }
  4394. this._iterationOrder = [];
  4395. var iterator = this._iterator;
  4396. if (!this._unfilteredIterationOrder && !this._filter) {
  4397. for (iterator.first(); iterator.hasNext(); iterator.next())
  4398. this._iterationOrder.push(iterator.index());
  4399. } else if (!this._unfilteredIterationOrder) {
  4400. for (iterator.first(); iterator.hasNext(); iterator.next()) {
  4401. if (this._filter(iterator.item()))
  4402. this._iterationOrder.push(iterator.index());
  4403. }
  4404. } else {
  4405. var order = this._unfilteredIterationOrder.constructor === Array ?
  4406. this._unfilteredIterationOrder : this._unfilteredIterationOrder.slice(0);
  4407. for (var i = 0, l = order.length; i < l; ++i) {
  4408. iterator.setIndex(order[i]);
  4409. if (this._filter(iterator.item()))
  4410. this._iterationOrder.push(iterator.index());
  4411. }
  4412. this._unfilteredIterationOrder = null;
  4413. }
  4414. },
  4415.  
  4416. first: function()
  4417. {
  4418. this._position = 0;
  4419. },
  4420.  
  4421. hasNext: function()
  4422. {
  4423. return this._position < this._iterationOrder.length;
  4424. },
  4425.  
  4426. isEmpty: function()
  4427. {
  4428. if (this._iterationOrder)
  4429. return !this._iterationOrder.length;
  4430. if (this._unfilteredIterationOrder && !this._filter)
  4431. return !this._unfilteredIterationOrder.length;
  4432. var iterator = this._iterator;
  4433. if (!this._unfilteredIterationOrder && !this._filter) {
  4434. iterator.first();
  4435. return !iterator.hasNext();
  4436. } else if (!this._unfilteredIterationOrder) {
  4437. for (iterator.first(); iterator.hasNext(); iterator.next())
  4438. if (this._filter(iterator.item()))
  4439. return false;
  4440. } else {
  4441. var order = this._unfilteredIterationOrder.constructor === Array ?
  4442. this._unfilteredIterationOrder : this._unfilteredIterationOrder.slice(0);
  4443. for (var i = 0, l = order.length; i < l; ++i) {
  4444. iterator.setIndex(order[i]);
  4445. if (this._filter(iterator.item()))
  4446. return false;
  4447. }
  4448. }
  4449. return true;
  4450. },
  4451.  
  4452. item: function()
  4453. {
  4454. this._iterator.setIndex(this._iterationOrder[this._position]);
  4455. return this._iterator.item();
  4456. },
  4457.  
  4458. get length()
  4459. {
  4460. this._createIterationOrder();
  4461. return this._iterationOrder.length;
  4462. },
  4463.  
  4464. next: function()
  4465. {
  4466. ++this._position;
  4467. },
  4468.  
  4469.  
  4470. serializeItemsRange: function(begin, end)
  4471. {
  4472. this._createIterationOrder();
  4473. if (begin > end)
  4474. throw new Error("Start position > end position: " + begin + " > " + end);
  4475. if (end >= this._iterationOrder.length)
  4476. end = this._iterationOrder.length;
  4477. if (this._sortedPrefixLength < end) {
  4478. this.sort(this._currentComparator, this._sortedPrefixLength, this._iterationOrder.length - 1, end - this._sortedPrefixLength);
  4479. this._sortedPrefixLength = end;
  4480. }
  4481.  
  4482. this._position = begin;
  4483. var startPosition = this._position;
  4484. var count = end - begin;
  4485. var result = new Array(count);
  4486. for (var i = 0 ; i < count && this.hasNext(); ++i, this.next())
  4487. result[i] = this.serializeItem(this.item());
  4488. result.length = i;
  4489. result.totalLength = this._iterationOrder.length;
  4490.  
  4491. result.startPosition = startPosition;
  4492. result.endPosition = this._position;
  4493. return result;
  4494. },
  4495.  
  4496. sortAll: function()
  4497. {
  4498. this._createIterationOrder();
  4499. if (this._sortedPrefixLength === this._iterationOrder.length)
  4500. return;
  4501. this.sort(this._currentComparator, this._sortedPrefixLength, this._iterationOrder.length - 1, this._iterationOrder.length);
  4502. this._sortedPrefixLength = this._iterationOrder.length;
  4503. },
  4504.  
  4505. sortAndRewind: function(comparator)
  4506. {
  4507. this._currentComparator = comparator;
  4508. this._sortedPrefixLength = 0;
  4509. this.first();
  4510. }
  4511. }
  4512.  
  4513. WebInspector.HeapSnapshotFilteredOrderedIterator.prototype.createComparator = function(fieldNames)
  4514. {
  4515. return {fieldName1:fieldNames[0], ascending1:fieldNames[1], fieldName2:fieldNames[2], ascending2:fieldNames[3]};
  4516. }
  4517.  
  4518.  
  4519. WebInspector.HeapSnapshotEdgesProvider = function(snapshot, filter, edgesIter)
  4520. {
  4521. this.snapshot = snapshot;
  4522. WebInspector.HeapSnapshotFilteredOrderedIterator.call(this, edgesIter, filter);
  4523. }
  4524.  
  4525. WebInspector.HeapSnapshotEdgesProvider.prototype = {
  4526. serializeItem: function(edge)
  4527. {
  4528. return {
  4529. name: edge.name(),
  4530. propertyAccessor: edge.toString(),
  4531. node: WebInspector.HeapSnapshotNodesProvider.prototype.serializeItem(edge.node()),
  4532. nodeIndex: edge.nodeIndex(),
  4533. type: edge.type(),
  4534. distanceToWindow: edge.node().distanceToWindow()
  4535. };
  4536. },
  4537.  
  4538. sort: function(comparator, leftBound, rightBound, count)
  4539. {
  4540. var fieldName1 = comparator.fieldName1;
  4541. var fieldName2 = comparator.fieldName2;
  4542. var ascending1 = comparator.ascending1;
  4543. var ascending2 = comparator.ascending2;
  4544.  
  4545. var edgeA = this._iterator.item().clone();
  4546. var edgeB = edgeA.clone();
  4547. var nodeA = new WebInspector.HeapSnapshotNode(this.snapshot);
  4548. var nodeB = new WebInspector.HeapSnapshotNode(this.snapshot);
  4549.  
  4550. function compareEdgeFieldName(ascending, indexA, indexB)
  4551. {
  4552. edgeA.edgeIndex = indexA;
  4553. edgeB.edgeIndex = indexB;
  4554. if (edgeB.name() === "__proto__") return -1;
  4555. if (edgeA.name() === "__proto__") return 1;
  4556. var result =
  4557. edgeA.hasStringName() === edgeB.hasStringName() ?
  4558. (edgeA.name() < edgeB.name() ? -1 : (edgeA.name() > edgeB.name() ? 1 : 0)) :
  4559. (edgeA.hasStringName() ? -1 : 1);
  4560. return ascending ? result : -result;
  4561. }
  4562.  
  4563. function compareNodeField(fieldName, ascending, indexA, indexB)
  4564. {
  4565. edgeA.edgeIndex = indexA;
  4566. nodeA.nodeIndex = edgeA.nodeIndex();
  4567. var valueA = nodeA[fieldName]();
  4568.  
  4569. edgeB.edgeIndex = indexB;
  4570. nodeB.nodeIndex = edgeB.nodeIndex();
  4571. var valueB = nodeB[fieldName]();
  4572.  
  4573. var result = valueA < valueB ? -1 : (valueA > valueB ? 1 : 0);
  4574. return ascending ? result : -result;
  4575. }
  4576.  
  4577. function compareEdgeAndNode(indexA, indexB) {
  4578. var result = compareEdgeFieldName(ascending1, indexA, indexB);
  4579. if (result === 0)
  4580. result = compareNodeField(fieldName2, ascending2, indexA, indexB);
  4581. return result;
  4582. }
  4583.  
  4584. function compareNodeAndEdge(indexA, indexB) {
  4585. var result = compareNodeField(fieldName1, ascending1, indexA, indexB);
  4586. if (result === 0)
  4587. result = compareEdgeFieldName(ascending2, indexA, indexB);
  4588. return result;
  4589. }
  4590.  
  4591. function compareNodeAndNode(indexA, indexB) {
  4592. var result = compareNodeField(fieldName1, ascending1, indexA, indexB);
  4593. if (result === 0)
  4594. result = compareNodeField(fieldName2, ascending2, indexA, indexB);
  4595. return result;
  4596. }
  4597.  
  4598. if (fieldName1 === "!edgeName")
  4599. this._iterationOrder.sortRange(compareEdgeAndNode, leftBound, rightBound, count);
  4600. else if (fieldName2 === "!edgeName")
  4601. this._iterationOrder.sortRange(compareNodeAndEdge, leftBound, rightBound, count);
  4602. else
  4603. this._iterationOrder.sortRange(compareNodeAndNode, leftBound, rightBound, count);
  4604. },
  4605.  
  4606. __proto__: WebInspector.HeapSnapshotFilteredOrderedIterator.prototype
  4607. }
  4608.  
  4609.  
  4610.  
  4611. WebInspector.HeapSnapshotNodesProvider = function(snapshot, filter, nodeIndexes)
  4612. {
  4613. this.snapshot = snapshot;
  4614. WebInspector.HeapSnapshotFilteredOrderedIterator.call(this, snapshot._allNodes(), filter, nodeIndexes);
  4615. }
  4616.  
  4617. WebInspector.HeapSnapshotNodesProvider.prototype = {
  4618. nodePosition: function(snapshotObjectId)
  4619. {
  4620. this._createIterationOrder();
  4621. if (this.isEmpty())
  4622. return -1;
  4623. this.sortAll();
  4624.  
  4625. var node = new WebInspector.HeapSnapshotNode(this.snapshot);
  4626. for (var i = 0; i < this._iterationOrder.length; i++) {
  4627. node.nodeIndex = this._iterationOrder[i];
  4628. if (node.id() === snapshotObjectId)
  4629. return i;
  4630. }
  4631. return -1;
  4632. },
  4633.  
  4634. serializeItem: function(node)
  4635. {
  4636. return {
  4637. id: node.id(),
  4638. name: node.name(),
  4639. distanceToWindow: node.distanceToWindow(),
  4640. nodeIndex: node.nodeIndex,
  4641. retainedSize: node.retainedSize(),
  4642. selfSize: node.selfSize(),
  4643. type: node.type(),
  4644. flags: node.flags()
  4645. };
  4646. },
  4647.  
  4648. sort: function(comparator, leftBound, rightBound, count)
  4649. {
  4650. var fieldName1 = comparator.fieldName1;
  4651. var fieldName2 = comparator.fieldName2;
  4652. var ascending1 = comparator.ascending1;
  4653. var ascending2 = comparator.ascending2;
  4654.  
  4655. var nodeA = new WebInspector.HeapSnapshotNode(this.snapshot);
  4656. var nodeB = new WebInspector.HeapSnapshotNode(this.snapshot);
  4657.  
  4658. function sortByNodeField(fieldName, ascending)
  4659. {
  4660. var valueOrFunctionA = nodeA[fieldName];
  4661. var valueA = typeof valueOrFunctionA !== "function" ? valueOrFunctionA : valueOrFunctionA.call(nodeA);
  4662. var valueOrFunctionB = nodeB[fieldName];
  4663. var valueB = typeof valueOrFunctionB !== "function" ? valueOrFunctionB : valueOrFunctionB.call(nodeB);
  4664. var result = valueA < valueB ? -1 : (valueA > valueB ? 1 : 0);
  4665. return ascending ? result : -result;
  4666. }
  4667.  
  4668. function sortByComparator(indexA, indexB) {
  4669. nodeA.nodeIndex = indexA;
  4670. nodeB.nodeIndex = indexB;
  4671. var result = sortByNodeField(fieldName1, ascending1);
  4672. if (result === 0)
  4673. result = sortByNodeField(fieldName2, ascending2);
  4674. return result;
  4675. }
  4676.  
  4677. this._iterationOrder.sortRange(sortByComparator, leftBound, rightBound, count);
  4678. },
  4679.  
  4680. __proto__: WebInspector.HeapSnapshotFilteredOrderedIterator.prototype
  4681. }
  4682.  
  4683. ;
  4684.  
  4685.  
  4686.  
  4687. WebInspector.HeapSnapshotSortableDataGrid = function(columns)
  4688. {
  4689. WebInspector.DataGrid.call(this, columns);
  4690.  
  4691.  
  4692. this._recursiveSortingDepth = 0;
  4693.  
  4694. this._highlightedNode = null;
  4695.  
  4696. this._populatedAndSorted = false;
  4697. this.addEventListener("sorting complete", this._sortingComplete, this);
  4698. this.addEventListener("sorting changed", this.sortingChanged, this);
  4699. }
  4700.  
  4701. WebInspector.HeapSnapshotSortableDataGrid.Events = {
  4702. ContentShown: "ContentShown"
  4703. }
  4704.  
  4705. WebInspector.HeapSnapshotSortableDataGrid.prototype = {
  4706.  
  4707. defaultPopulateCount: function()
  4708. {
  4709. return 100;
  4710. },
  4711.  
  4712. dispose: function()
  4713. {
  4714. var children = this.topLevelNodes();
  4715. for (var i = 0, l = children.length; i < l; ++i)
  4716. children[i].dispose();
  4717. },
  4718.  
  4719.  
  4720. wasShown: function()
  4721. {
  4722. if (this._populatedAndSorted)
  4723. this.dispatchEventToListeners(WebInspector.HeapSnapshotSortableDataGrid.Events.ContentShown, this);
  4724. },
  4725.  
  4726. _sortingComplete: function()
  4727. {
  4728. this.removeEventListener("sorting complete", this._sortingComplete, this);
  4729. this._populatedAndSorted = true;
  4730. this.dispatchEventToListeners(WebInspector.HeapSnapshotSortableDataGrid.Events.ContentShown, this);
  4731. },
  4732.  
  4733.  
  4734. willHide: function()
  4735. {
  4736. this._clearCurrentHighlight();
  4737. },
  4738.  
  4739.  
  4740. populateContextMenu: function(profilesPanel, contextMenu, event)
  4741. {
  4742. var td = event.target.enclosingNodeOrSelfWithNodeName("td");
  4743. if (!td)
  4744. return;
  4745. var node = td.heapSnapshotNode;
  4746. if (node instanceof WebInspector.HeapSnapshotInstanceNode || node instanceof WebInspector.HeapSnapshotObjectNode) {
  4747. function revealInDominatorsView()
  4748. {
  4749. profilesPanel.showObject(node.snapshotNodeId, "Dominators");
  4750. }
  4751. contextMenu.appendItem(WebInspector.UIString("Reveal in Dominators View"), revealInDominatorsView.bind(this));
  4752. } else if (node instanceof WebInspector.HeapSnapshotDominatorObjectNode) {
  4753. function revealInSummaryView()
  4754. {
  4755. profilesPanel.showObject(node.snapshotNodeId, "Summary");
  4756. }
  4757. contextMenu.appendItem(WebInspector.UIString("Reveal in Summary View"), revealInSummaryView.bind(this));
  4758. }
  4759. },
  4760.  
  4761. resetSortingCache: function()
  4762. {
  4763. delete this._lastSortColumnIdentifier;
  4764. delete this._lastSortAscending;
  4765. },
  4766.  
  4767. topLevelNodes: function()
  4768. {
  4769. return this.rootNode().children;
  4770. },
  4771.  
  4772.  
  4773. highlightObjectByHeapSnapshotId: function(heapSnapshotObjectId)
  4774. {
  4775. },
  4776.  
  4777.  
  4778. highlightNode: function(node)
  4779. {
  4780. var prevNode = this._highlightedNode;
  4781. this._clearCurrentHighlight();
  4782. this._highlightedNode = node;
  4783. this._highlightedNode.element.addStyleClass("highlighted-row");
  4784.  
  4785. if (node === prevNode) {
  4786. var element = node.element;
  4787. var parent = element.parentElement;
  4788. var nextSibling = element.nextSibling;
  4789. parent.removeChild(element);
  4790. parent.insertBefore(element, nextSibling);
  4791. }
  4792. },
  4793.  
  4794. nodeWasDetached: function(node)
  4795. {
  4796. if (this._highlightedNode === node)
  4797. this._clearCurrentHighlight();
  4798. },
  4799.  
  4800. _clearCurrentHighlight: function()
  4801. {
  4802. if (!this._highlightedNode)
  4803. return
  4804. this._highlightedNode.element.removeStyleClass("highlighted-row");
  4805. this._highlightedNode = null;
  4806. },
  4807.  
  4808. changeNameFilter: function(filter)
  4809. {
  4810. filter = filter.toLowerCase();
  4811. var children = this.topLevelNodes();
  4812. for (var i = 0, l = children.length; i < l; ++i) {
  4813. var node = children[i];
  4814. if (node.depth === 0)
  4815. node.revealed = node._name.toLowerCase().indexOf(filter) !== -1;
  4816. }
  4817. this.updateVisibleNodes();
  4818. },
  4819.  
  4820. sortingChanged: function()
  4821. {
  4822. var sortAscending = this.sortOrder === "ascending";
  4823. var sortColumnIdentifier = this.sortColumnIdentifier;
  4824. if (this._lastSortColumnIdentifier === sortColumnIdentifier && this._lastSortAscending === sortAscending)
  4825. return;
  4826. this._lastSortColumnIdentifier = sortColumnIdentifier;
  4827. this._lastSortAscending = sortAscending;
  4828. var sortFields = this._sortFields(sortColumnIdentifier, sortAscending);
  4829.  
  4830. function SortByTwoFields(nodeA, nodeB)
  4831. {
  4832. var field1 = nodeA[sortFields[0]];
  4833. var field2 = nodeB[sortFields[0]];
  4834. var result = field1 < field2 ? -1 : (field1 > field2 ? 1 : 0);
  4835. if (!sortFields[1])
  4836. result = -result;
  4837. if (result !== 0)
  4838. return result;
  4839. field1 = nodeA[sortFields[2]];
  4840. field2 = nodeB[sortFields[2]];
  4841. result = field1 < field2 ? -1 : (field1 > field2 ? 1 : 0);
  4842. if (!sortFields[3])
  4843. result = -result;
  4844. return result;
  4845. }
  4846. this._performSorting(SortByTwoFields);
  4847. },
  4848.  
  4849. _performSorting: function(sortFunction)
  4850. {
  4851. this.recursiveSortingEnter();
  4852. var children = this._topLevelNodes;
  4853. this.rootNode().removeChildren();
  4854. children.sort(sortFunction);
  4855. for (var i = 0, l = children.length; i < l; ++i) {
  4856. var child = children[i];
  4857. this.appendChildAfterSorting(child);
  4858. if (child.expanded)
  4859. child.sort();
  4860. }
  4861. this.updateVisibleNodes();
  4862. this.recursiveSortingLeave();
  4863. },
  4864.  
  4865. appendChildAfterSorting: function(child)
  4866. {
  4867. var revealed = child.revealed;
  4868. this.rootNode().appendChild(child);
  4869. child.revealed = revealed;
  4870. },
  4871.  
  4872. updateVisibleNodes: function()
  4873. {
  4874. },
  4875.  
  4876. recursiveSortingEnter: function()
  4877. {
  4878. ++this._recursiveSortingDepth;
  4879. },
  4880.  
  4881. recursiveSortingLeave: function()
  4882. {
  4883. if (!this._recursiveSortingDepth)
  4884. return;
  4885. if (!--this._recursiveSortingDepth)
  4886. this.dispatchEventToListeners("sorting complete");
  4887. },
  4888.  
  4889. __proto__: WebInspector.DataGrid.prototype
  4890. }
  4891.  
  4892.  
  4893.  
  4894.  
  4895. WebInspector.HeapSnapshotViewportDataGrid = function(columns)
  4896. {
  4897. WebInspector.HeapSnapshotSortableDataGrid.call(this, columns);
  4898. this.scrollContainer.addEventListener("scroll", this._onScroll.bind(this), true);
  4899. this._topLevelNodes = [];
  4900. this._topPadding = new WebInspector.HeapSnapshotPaddingNode();
  4901. this._bottomPadding = new WebInspector.HeapSnapshotPaddingNode();
  4902.  
  4903. this._nodeToHighlightAfterScroll = null;
  4904. }
  4905.  
  4906. WebInspector.HeapSnapshotViewportDataGrid.prototype = {
  4907. topLevelNodes: function()
  4908. {
  4909. return this._topLevelNodes;
  4910. },
  4911.  
  4912. appendChildAfterSorting: function(child)
  4913. {
  4914.  
  4915. },
  4916.  
  4917. updateVisibleNodes: function()
  4918. {
  4919. var scrollTop = this.scrollContainer.scrollTop;
  4920.  
  4921. var viewPortHeight = this.scrollContainer.offsetHeight;
  4922.  
  4923. this._removePaddingRows();
  4924.  
  4925. var children = this._topLevelNodes;
  4926.  
  4927. var i = 0;
  4928. var topPadding = 0;
  4929. while (i < children.length) {
  4930. if (children[i].revealed) {
  4931. var newTop = topPadding + children[i].nodeHeight();
  4932. if (newTop > scrollTop)
  4933. break;
  4934. topPadding = newTop;
  4935. }
  4936. ++i;
  4937. }
  4938.  
  4939. this.rootNode().removeChildren();
  4940.  
  4941. var heightToFill = viewPortHeight + (scrollTop - topPadding);
  4942. var filledHeight = 0;
  4943. while (i < children.length && filledHeight < heightToFill) {
  4944. if (children[i].revealed) {
  4945. this.rootNode().appendChild(children[i]);
  4946. filledHeight += children[i].nodeHeight();
  4947. }
  4948. ++i;
  4949. }
  4950.  
  4951. var bottomPadding = 0;
  4952. while (i < children.length) {
  4953. bottomPadding += children[i].nodeHeight();
  4954. ++i;
  4955. }
  4956.  
  4957. this._addPaddingRows(topPadding, bottomPadding);
  4958. },
  4959.  
  4960. appendTopLevelNode: function(node)
  4961. {
  4962. this._topLevelNodes.push(node);
  4963. },
  4964.  
  4965. removeTopLevelNodes: function()
  4966. {
  4967. this.rootNode().removeChildren();
  4968. this._topLevelNodes = [];
  4969. },
  4970.  
  4971.  
  4972. highlightNode: function(node)
  4973. {
  4974. if (this._isScrolledIntoView(node.element))
  4975. WebInspector.HeapSnapshotSortableDataGrid.prototype.highlightNode.call(this, node);
  4976. else {
  4977. node.element.scrollIntoViewIfNeeded(true);
  4978. this._nodeToHighlightAfterScroll = node;
  4979. }
  4980. },
  4981.  
  4982. _isScrolledIntoView: function(element)
  4983. {
  4984. var viewportTop = this.scrollContainer.scrollTop;
  4985. var viewportBottom = viewportTop + this.scrollContainer.clientHeight;
  4986. var elemTop = element.offsetTop
  4987. var elemBottom = elemTop + element.offsetHeight;
  4988. return elemBottom <= viewportBottom && elemTop >= viewportTop;
  4989. },
  4990.  
  4991. _addPaddingRows: function(top, bottom)
  4992. {
  4993. if (this._topPadding.element.parentNode !== this.dataTableBody)
  4994. this.dataTableBody.insertBefore(this._topPadding.element, this.dataTableBody.firstChild);
  4995. if (this._bottomPadding.element.parentNode !== this.dataTableBody)
  4996. this.dataTableBody.insertBefore(this._bottomPadding.element, this.dataTableBody.lastChild);
  4997. this._topPadding.setHeight(top);
  4998. this._bottomPadding.setHeight(bottom);
  4999. },
  5000.  
  5001. _removePaddingRows: function()
  5002. {
  5003. this._bottomPadding.removeFromTable();
  5004. this._topPadding.removeFromTable();
  5005. },
  5006.  
  5007. onResize: function()
  5008. {
  5009. WebInspector.HeapSnapshotSortableDataGrid.prototype.onResize.call(this);
  5010. this.updateVisibleNodes();
  5011. },
  5012.  
  5013. _onScroll: function(event)
  5014. {
  5015. this.updateVisibleNodes();
  5016.  
  5017. if (this._nodeToHighlightAfterScroll) {
  5018. WebInspector.HeapSnapshotSortableDataGrid.prototype.highlightNode.call(this, this._nodeToHighlightAfterScroll);
  5019. this._nodeToHighlightAfterScroll = null;
  5020. }
  5021. },
  5022.  
  5023. __proto__: WebInspector.HeapSnapshotSortableDataGrid.prototype
  5024. }
  5025.  
  5026.  
  5027. WebInspector.HeapSnapshotPaddingNode = function()
  5028. {
  5029. this.element = document.createElement("tr");
  5030. this.element.addStyleClass("revealed");
  5031. }
  5032.  
  5033. WebInspector.HeapSnapshotPaddingNode.prototype = {
  5034. setHeight: function(height)
  5035. {
  5036. this.element.style.height = height + "px";
  5037. },
  5038. removeFromTable: function()
  5039. {
  5040. var parent = this.element.parentNode;
  5041. if (parent)
  5042. parent.removeChild(this.element);
  5043. }
  5044. }
  5045.  
  5046.  
  5047.  
  5048. WebInspector.HeapSnapshotContainmentDataGrid = function(columns)
  5049. {
  5050. columns = columns || {
  5051. object: { title: WebInspector.UIString("Object"), disclosure: true, sortable: true },
  5052. shallowSize: { title: WebInspector.UIString("Shallow Size"), width: "120px", sortable: true },
  5053. retainedSize: { title: WebInspector.UIString("Retained Size"), width: "120px", sortable: true, sort: "descending" }
  5054. };
  5055. WebInspector.HeapSnapshotSortableDataGrid.call(this, columns);
  5056. }
  5057.  
  5058. WebInspector.HeapSnapshotContainmentDataGrid.prototype = {
  5059. setDataSource: function(snapshot, nodeIndex)
  5060. {
  5061. this.snapshot = snapshot;
  5062. var node = new WebInspector.HeapSnapshotNode(snapshot, nodeIndex || snapshot.rootNodeIndex);
  5063. var fakeEdge = { node: node };
  5064. this.setRootNode(new WebInspector.HeapSnapshotObjectNode(this, false, fakeEdge, null));
  5065. this.rootNode().sort();
  5066. },
  5067.  
  5068. sortingChanged: function()
  5069. {
  5070. this.rootNode().sort();
  5071. },
  5072.  
  5073. __proto__: WebInspector.HeapSnapshotSortableDataGrid.prototype
  5074. }
  5075.  
  5076.  
  5077.  
  5078. WebInspector.HeapSnapshotRetainmentDataGrid = function()
  5079. {
  5080. this.showRetainingEdges = true;
  5081. var columns = {
  5082. object: { title: WebInspector.UIString("Object"), disclosure: true, sortable: true },
  5083. shallowSize: { title: WebInspector.UIString("Shallow Size"), width: "120px", sortable: true },
  5084. retainedSize: { title: WebInspector.UIString("Retained Size"), width: "120px", sortable: true },
  5085. distanceToWindow: { title: WebInspector.UIString("Distance"), width: "80px", sortable: true, sort: "ascending" }
  5086. };
  5087. WebInspector.HeapSnapshotContainmentDataGrid.call(this, columns);
  5088. }
  5089.  
  5090. WebInspector.HeapSnapshotRetainmentDataGrid.prototype = {
  5091. _sortFields: function(sortColumn, sortAscending)
  5092. {
  5093. return {
  5094. object: ["_name", sortAscending, "_count", false],
  5095. count: ["_count", sortAscending, "_name", true],
  5096. shallowSize: ["_shallowSize", sortAscending, "_name", true],
  5097. retainedSize: ["_retainedSize", sortAscending, "_name", true],
  5098. distanceToWindow: ["_distanceToWindow", sortAscending, "_name", true]
  5099. }[sortColumn];
  5100. },
  5101.  
  5102. reset: function()
  5103. {
  5104. this.rootNode().removeChildren();
  5105. this.resetSortingCache();
  5106. },
  5107.  
  5108. __proto__: WebInspector.HeapSnapshotContainmentDataGrid.prototype
  5109. }
  5110.  
  5111.  
  5112.  
  5113. WebInspector.HeapSnapshotConstructorsDataGrid = function()
  5114. {
  5115. var columns = {
  5116. object: { title: WebInspector.UIString("Constructor"), disclosure: true, sortable: true },
  5117. distanceToWindow: { title: WebInspector.UIString("Distance"), width: "90px", sortable: true },
  5118. count: { title: WebInspector.UIString("Objects Count"), width: "90px", sortable: true },
  5119. shallowSize: { title: WebInspector.UIString("Shallow Size"), width: "120px", sortable: true },
  5120. retainedSize: { title: WebInspector.UIString("Retained Size"), width: "120px", sort: "descending", sortable: true }
  5121. };
  5122. WebInspector.HeapSnapshotViewportDataGrid.call(this, columns);
  5123. this._profileIndex = -1;
  5124. this._topLevelNodes = [];
  5125.  
  5126. this._objectIdToSelect = null;
  5127. }
  5128.  
  5129. WebInspector.HeapSnapshotConstructorsDataGrid.prototype = {
  5130. _sortFields: function(sortColumn, sortAscending)
  5131. {
  5132. return {
  5133. object: ["_name", sortAscending, "_count", false],
  5134. distanceToWindow: ["_distanceToWindow", sortAscending, "_retainedSize", true],
  5135. count: ["_count", sortAscending, "_name", true],
  5136. shallowSize: ["_shallowSize", sortAscending, "_name", true],
  5137. retainedSize: ["_retainedSize", sortAscending, "_name", true]
  5138. }[sortColumn];
  5139. },
  5140.  
  5141.  
  5142. highlightObjectByHeapSnapshotId: function(id)
  5143. {
  5144. if (!this.snapshot) {
  5145. this._objectIdToSelect = id;
  5146. return;
  5147. }
  5148.  
  5149. function didGetClassName(className)
  5150. {
  5151. var constructorNodes = this.topLevelNodes();
  5152. for (var i = 0; i < constructorNodes.length; i++) {
  5153. var parent = constructorNodes[i];
  5154. if (parent._name === className) {
  5155. parent.revealNodeBySnapshotObjectId(parseInt(id, 10));
  5156. return;
  5157. }
  5158. }
  5159. }
  5160. this.snapshot.nodeClassName(parseInt(id, 10), didGetClassName.bind(this));
  5161. },
  5162.  
  5163. setDataSource: function(snapshot)
  5164. {
  5165. this.snapshot = snapshot;
  5166. if (this._profileIndex === -1)
  5167. this._populateChildren();
  5168.  
  5169. if (this._objectIdToSelect) {
  5170. this.highlightObjectByHeapSnapshotId(this._objectIdToSelect);
  5171. this._objectIdToSelect = null;
  5172. }
  5173. },
  5174.  
  5175. _aggregatesReceived: function(key, aggregates)
  5176. {
  5177. for (var constructor in aggregates)
  5178. this.appendTopLevelNode(new WebInspector.HeapSnapshotConstructorNode(this, constructor, aggregates[constructor], key));
  5179. this.sortingChanged();
  5180. },
  5181.  
  5182. _populateChildren: function()
  5183. {
  5184.  
  5185. this.dispose();
  5186. this.removeTopLevelNodes();
  5187. this.resetSortingCache();
  5188.  
  5189. var key = this._profileIndex === -1 ? "allObjects" : this._minNodeId + ".." + this._maxNodeId;
  5190. var filter = this._profileIndex === -1 ? null : "function(node) { var id = node.id(); return id > " + this._minNodeId + " && id <= " + this._maxNodeId + "; }";
  5191.  
  5192. this.snapshot.aggregates(false, key, filter, this._aggregatesReceived.bind(this, key));
  5193. },
  5194.  
  5195. filterSelectIndexChanged: function(profiles, profileIndex)
  5196. {
  5197. this._profileIndex = profileIndex;
  5198.  
  5199. delete this._maxNodeId;
  5200. delete this._minNodeId;
  5201.  
  5202. if (this._profileIndex !== -1) {
  5203. this._minNodeId = profileIndex > 0 ? profiles[profileIndex - 1].maxJSObjectId : 0;
  5204. this._maxNodeId = profiles[profileIndex].maxJSObjectId;
  5205. }
  5206.  
  5207. this._populateChildren();
  5208. },
  5209.  
  5210. __proto__: WebInspector.HeapSnapshotViewportDataGrid.prototype
  5211. }
  5212.  
  5213.  
  5214.  
  5215. WebInspector.HeapSnapshotDiffDataGrid = function()
  5216. {
  5217. var columns = {
  5218. object: { title: WebInspector.UIString("Constructor"), disclosure: true, sortable: true },
  5219. addedCount: { title: WebInspector.UIString("# New"), width: "72px", sortable: true },
  5220. removedCount: { title: WebInspector.UIString("# Deleted"), width: "72px", sortable: true },
  5221. countDelta: { title: "# Delta", width: "64px", sortable: true },
  5222. addedSize: { title: WebInspector.UIString("Alloc. Size"), width: "72px", sortable: true, sort: "descending" },
  5223. removedSize: { title: WebInspector.UIString("Freed Size"), width: "72px", sortable: true },
  5224. sizeDelta: { title: "Size Delta", width: "72px", sortable: true }
  5225. };
  5226. WebInspector.HeapSnapshotViewportDataGrid.call(this, columns);
  5227. }
  5228.  
  5229. WebInspector.HeapSnapshotDiffDataGrid.prototype = {
  5230.  
  5231. defaultPopulateCount: function()
  5232. {
  5233. return 50;
  5234. },
  5235.  
  5236. _sortFields: function(sortColumn, sortAscending)
  5237. {
  5238. return {
  5239. object: ["_name", sortAscending, "_count", false],
  5240. addedCount: ["_addedCount", sortAscending, "_name", true],
  5241. removedCount: ["_removedCount", sortAscending, "_name", true],
  5242. countDelta: ["_countDelta", sortAscending, "_name", true],
  5243. addedSize: ["_addedSize", sortAscending, "_name", true],
  5244. removedSize: ["_removedSize", sortAscending, "_name", true],
  5245. sizeDelta: ["_sizeDelta", sortAscending, "_name", true]
  5246. }[sortColumn];
  5247. },
  5248.  
  5249. setDataSource: function(snapshot)
  5250. {
  5251. this.snapshot = snapshot;
  5252. },
  5253.  
  5254.  
  5255. setBaseDataSource: function(baseSnapshot)
  5256. {
  5257. this.baseSnapshot = baseSnapshot;
  5258. this.dispose();
  5259. this.removeTopLevelNodes();
  5260. this.resetSortingCache();
  5261. if (this.baseSnapshot === this.snapshot) {
  5262. this.dispatchEventToListeners("sorting complete");
  5263. return;
  5264. }
  5265. this._populateChildren();
  5266. },
  5267.  
  5268. _populateChildren: function()
  5269. {
  5270. function aggregatesForDiffReceived(aggregatesForDiff)
  5271. {
  5272. this.snapshot.calculateSnapshotDiff(this.baseSnapshot.uid, aggregatesForDiff, didCalculateSnapshotDiff.bind(this));
  5273. function didCalculateSnapshotDiff(diffByClassName)
  5274. {
  5275. for (var className in diffByClassName) {
  5276. var diff = diffByClassName[className];
  5277. this.appendTopLevelNode(new WebInspector.HeapSnapshotDiffNode(this, className, diff));
  5278. }
  5279. this.sortingChanged();
  5280. }
  5281. }
  5282.  
  5283.  
  5284.  
  5285. this.baseSnapshot.aggregatesForDiff(aggregatesForDiffReceived.bind(this));
  5286. },
  5287.  
  5288. __proto__: WebInspector.HeapSnapshotViewportDataGrid.prototype
  5289. }
  5290.  
  5291.  
  5292.  
  5293. WebInspector.HeapSnapshotDominatorsDataGrid = function()
  5294. {
  5295. var columns = {
  5296. object: { title: WebInspector.UIString("Object"), disclosure: true, sortable: true },
  5297. shallowSize: { title: WebInspector.UIString("Shallow Size"), width: "120px", sortable: true },
  5298. retainedSize: { title: WebInspector.UIString("Retained Size"), width: "120px", sort: "descending", sortable: true }
  5299. };
  5300. WebInspector.HeapSnapshotSortableDataGrid.call(this, columns);
  5301. this._objectIdToSelect = null;
  5302. }
  5303.  
  5304. WebInspector.HeapSnapshotDominatorsDataGrid.prototype = {
  5305.  
  5306. defaultPopulateCount: function()
  5307. {
  5308. return 25;
  5309. },
  5310.  
  5311. setDataSource: function(snapshot)
  5312. {
  5313. this.snapshot = snapshot;
  5314.  
  5315. var fakeNode = { nodeIndex: this.snapshot.rootNodeIndex };
  5316. this.setRootNode(new WebInspector.HeapSnapshotDominatorObjectNode(this, fakeNode));
  5317. this.rootNode().sort();
  5318.  
  5319. if (this._objectIdToSelect) {
  5320. this.highlightObjectByHeapSnapshotId(this._objectIdToSelect);
  5321. this._objectIdToSelect = null;
  5322. }
  5323. },
  5324.  
  5325. sortingChanged: function()
  5326. {
  5327. this.rootNode().sort();
  5328. },
  5329.  
  5330.  
  5331. highlightObjectByHeapSnapshotId: function(id)
  5332. {
  5333. if (!this.snapshot) {
  5334. this._objectIdToSelect = id;
  5335. return;
  5336. }
  5337.  
  5338. function didGetDominators(dominatorIds)
  5339. {
  5340. if (!dominatorIds) {
  5341. WebInspector.log(WebInspector.UIString("Cannot find corresponding heap snapshot node"));
  5342. return;
  5343. }
  5344. var dominatorNode = this.rootNode();
  5345. expandNextDominator.call(this, dominatorIds, dominatorNode);
  5346. }
  5347.  
  5348. function expandNextDominator(dominatorIds, dominatorNode)
  5349. {
  5350. if (!dominatorNode) {
  5351. console.error("Cannot find dominator node");
  5352. return;
  5353. }
  5354. if (!dominatorIds.length) {
  5355. this.highlightNode(dominatorNode);
  5356. dominatorNode.element.scrollIntoViewIfNeeded(true);
  5357. return;
  5358. }
  5359. var snapshotObjectId = dominatorIds.pop();
  5360. dominatorNode.retrieveChildBySnapshotObjectId(snapshotObjectId, expandNextDominator.bind(this, dominatorIds));
  5361. }
  5362.  
  5363. this.snapshot.dominatorIdsForNode(parseInt(id, 10), didGetDominators.bind(this));
  5364. },
  5365.  
  5366. __proto__: WebInspector.HeapSnapshotSortableDataGrid.prototype
  5367. }
  5368.  
  5369. ;
  5370.  
  5371.  
  5372.  
  5373. WebInspector.HeapSnapshotGridNode = function(tree, hasChildren)
  5374. {
  5375. WebInspector.DataGridNode.call(this, null, hasChildren);
  5376. this._dataGrid = tree;
  5377. this._instanceCount = 0;
  5378.  
  5379. this._savedChildren = null;
  5380.  
  5381. this._retrievedChildrenRanges = [];
  5382. this.addEventListener("populate", this._populate, this);
  5383. }
  5384.  
  5385. WebInspector.HeapSnapshotGridNode.prototype = {
  5386.  
  5387. createProvider: function()
  5388. {
  5389. throw new Error("Needs implemented.");
  5390. },
  5391.  
  5392.  
  5393. _provider: function()
  5394. {
  5395. if (!this._providerObject)
  5396. this._providerObject = this.createProvider();
  5397. return this._providerObject;
  5398. },
  5399.  
  5400. createCell: function(columnIdentifier)
  5401. {
  5402. var cell = WebInspector.DataGridNode.prototype.createCell.call(this, columnIdentifier);
  5403. if (this._searchMatched)
  5404. cell.addStyleClass("highlight");
  5405. return cell;
  5406. },
  5407.  
  5408. collapse: function()
  5409. {
  5410. WebInspector.DataGridNode.prototype.collapse.call(this);
  5411. this._dataGrid.updateVisibleNodes();
  5412. },
  5413.  
  5414. dispose: function()
  5415. {
  5416. if (this._provider())
  5417. this._provider().dispose();
  5418. for (var node = this.children[0]; node; node = node.traverseNextNode(true, this, true))
  5419. if (node.dispose)
  5420. node.dispose();
  5421. },
  5422.  
  5423. _reachableFromWindow: false,
  5424.  
  5425. queryObjectContent: function(callback)
  5426. {
  5427. },
  5428.  
  5429.  
  5430. wasDetached: function()
  5431. {
  5432. this._dataGrid.nodeWasDetached(this);
  5433. },
  5434.  
  5435. _toPercentString: function(num)
  5436. {
  5437. return num.toFixed(0) + "\u2009%"; 
  5438. },
  5439.  
  5440.  
  5441. childForPosition: function(nodePosition)
  5442. {
  5443. var indexOfFirsChildInRange = 0;
  5444. for (var i = 0; i < this._retrievedChildrenRanges.length; i++) {
  5445. var range = this._retrievedChildrenRanges[i];
  5446. if (range.from <= nodePosition && nodePosition < range.to) {
  5447. var childIndex = indexOfFirsChildInRange + nodePosition - range.from;
  5448. return this.children[childIndex];
  5449. }
  5450. indexOfFirsChildInRange += range.to - range.from + 1;
  5451. }
  5452. return null;
  5453. },
  5454.  
  5455. _createValueCell: function(columnIdentifier)
  5456. {
  5457. var cell = document.createElement("td");
  5458. cell.className = columnIdentifier + "-column";
  5459. if (this.dataGrid.snapshot.totalSize !== 0) {
  5460. var div = document.createElement("div");
  5461. var valueSpan = document.createElement("span");
  5462. valueSpan.textContent = this.data[columnIdentifier];
  5463. div.appendChild(valueSpan);
  5464. var percentColumn = columnIdentifier + "-percent";
  5465. if (percentColumn in this.data) {
  5466. var percentSpan = document.createElement("span");
  5467. percentSpan.className = "percent-column";
  5468. percentSpan.textContent = this.data[percentColumn];
  5469. div.appendChild(percentSpan);
  5470. }
  5471. cell.appendChild(div);
  5472. }
  5473. return cell;
  5474. },
  5475.  
  5476. _populate: function(event)
  5477. {
  5478. this.removeEventListener("populate", this._populate, this);
  5479. function sorted()
  5480. {
  5481. this._populateChildren();
  5482. }
  5483. this._provider().sortAndRewind(this.comparator(), sorted.bind(this));
  5484. },
  5485.  
  5486. expandWithoutPopulate: function(callback)
  5487. {
  5488.  
  5489. this.removeEventListener("populate", this._populate, this);
  5490. this.expand();
  5491. this._provider().sortAndRewind(this.comparator(), callback);
  5492. },
  5493.  
  5494.  
  5495. _populateChildren: function(fromPosition, toPosition, afterPopulate)
  5496. {
  5497. fromPosition = fromPosition || 0;
  5498. toPosition = toPosition || fromPosition + this._dataGrid.defaultPopulateCount();
  5499. var firstNotSerializedPosition = fromPosition;
  5500. function serializeNextChunk()
  5501. {
  5502. if (firstNotSerializedPosition >= toPosition)
  5503. return;
  5504. var end = Math.min(firstNotSerializedPosition + this._dataGrid.defaultPopulateCount(), toPosition);
  5505. this._provider().serializeItemsRange(firstNotSerializedPosition, end, childrenRetrieved.bind(this));
  5506. firstNotSerializedPosition = end;
  5507. }
  5508. function insertRetrievedChild(item, insertionIndex)
  5509. {
  5510. if (this._savedChildren) {
  5511. var hash = this._childHashForEntity(item);
  5512. if (hash in this._savedChildren) {
  5513. this.insertChild(this._savedChildren[hash], insertionIndex);
  5514. return;
  5515. }
  5516. }
  5517. this.insertChild(this._createChildNode(item), insertionIndex);
  5518. }
  5519. function insertShowMoreButton(from, to, insertionIndex)
  5520. {
  5521. var button = new WebInspector.ShowMoreDataGridNode(this._populateChildren.bind(this), from, to, this._dataGrid.defaultPopulateCount());
  5522. this.insertChild(button, insertionIndex);
  5523. }
  5524. function childrenRetrieved(items)
  5525. {
  5526. var itemIndex = 0;
  5527. var itemPosition = items.startPosition;
  5528. var insertionIndex = 0;
  5529.  
  5530. if (!this._retrievedChildrenRanges.length) {
  5531. if (items.startPosition > 0) {
  5532. this._retrievedChildrenRanges.push({from: 0, to: 0});
  5533. insertShowMoreButton.call(this, 0, items.startPosition, insertionIndex++);
  5534. }
  5535. this._retrievedChildrenRanges.push({from: items.startPosition, to: items.endPosition});
  5536. for (var i = 0, l = items.length; i < l; ++i)
  5537. insertRetrievedChild.call(this, items[i], insertionIndex++);
  5538. if (items.endPosition < items.totalLength)
  5539. insertShowMoreButton.call(this, items.endPosition, items.totalLength, insertionIndex++);
  5540. } else {
  5541. var rangeIndex = 0;
  5542. var found = false;
  5543. var range;
  5544. while (rangeIndex < this._retrievedChildrenRanges.length) {
  5545. range = this._retrievedChildrenRanges[rangeIndex];
  5546. if (range.to >= itemPosition) {
  5547. found = true;
  5548. break;
  5549. }
  5550. insertionIndex += range.to - range.from;
  5551.  
  5552. if (range.to < items.totalLength)
  5553. insertionIndex += 1;
  5554. ++rangeIndex;
  5555. }
  5556.  
  5557. if (!found || items.startPosition < range.from) {
  5558.  
  5559. this.children[insertionIndex - 1].setEndPosition(items.startPosition);
  5560. insertShowMoreButton.call(this, items.startPosition, found ? range.from : items.totalLength, insertionIndex);
  5561. range = {from: items.startPosition, to: items.startPosition};
  5562. if (!found)
  5563. rangeIndex = this._retrievedChildrenRanges.length;
  5564. this._retrievedChildrenRanges.splice(rangeIndex, 0, range);
  5565. } else {
  5566. insertionIndex += itemPosition - range.from;
  5567. }
  5568.  
  5569.  
  5570.  
  5571.  
  5572. while (range.to < items.endPosition) {
  5573.  
  5574. var skipCount = range.to - itemPosition;
  5575. insertionIndex += skipCount;
  5576. itemIndex += skipCount;
  5577. itemPosition = range.to;
  5578.  
  5579.  
  5580. var nextRange = this._retrievedChildrenRanges[rangeIndex + 1];
  5581. var newEndOfRange = nextRange ? nextRange.from : items.totalLength;
  5582. if (newEndOfRange > items.endPosition)
  5583. newEndOfRange = items.endPosition;
  5584. while (itemPosition < newEndOfRange) {
  5585. insertRetrievedChild.call(this, items[itemIndex++], insertionIndex++);
  5586. ++itemPosition;
  5587. }
  5588.  
  5589. if (nextRange && newEndOfRange === nextRange.from) {
  5590. range.to = nextRange.to;
  5591.  
  5592. this.removeChild(this.children[insertionIndex]);
  5593. this._retrievedChildrenRanges.splice(rangeIndex + 1, 1);
  5594. } else {
  5595. range.to = newEndOfRange;
  5596.  
  5597. if (newEndOfRange === items.totalLength)
  5598. this.removeChild(this.children[insertionIndex]);
  5599. else
  5600. this.children[insertionIndex].setStartPosition(items.endPosition);
  5601. }
  5602. }
  5603. }
  5604.  
  5605.  
  5606. this._instanceCount += items.length;
  5607. if (firstNotSerializedPosition < toPosition) {
  5608. serializeNextChunk.call(this);
  5609. return;
  5610. }
  5611.  
  5612. if (afterPopulate)
  5613. afterPopulate();
  5614. this.dispatchEventToListeners("populate complete");
  5615. }
  5616. serializeNextChunk.call(this);
  5617. },
  5618.  
  5619. _saveChildren: function()
  5620. {
  5621. this._savedChildren = null;
  5622. for (var i = 0, childrenCount = this.children.length; i < childrenCount; ++i) {
  5623. var child = this.children[i];
  5624. if (!child.expanded)
  5625. continue;
  5626. if (!this._savedChildren)
  5627. this._savedChildren = {};
  5628. this._savedChildren[this._childHashForNode(child)] = child;
  5629. }
  5630. },
  5631.  
  5632. sort: function()
  5633. {
  5634. this._dataGrid.recursiveSortingEnter();
  5635. function afterSort()
  5636. {
  5637. this._saveChildren();
  5638. this.removeChildren();
  5639. this._retrievedChildrenRanges = [];
  5640.  
  5641. function afterPopulate()
  5642. {
  5643. for (var i = 0, l = this.children.length; i < l; ++i) {
  5644. var child = this.children[i];
  5645. if (child.expanded)
  5646. child.sort();
  5647. }
  5648. this._dataGrid.recursiveSortingLeave();
  5649. }
  5650. var instanceCount = this._instanceCount;
  5651. this._instanceCount = 0;
  5652. this._populateChildren(0, instanceCount, afterPopulate.bind(this));
  5653. }
  5654.  
  5655. this._provider().sortAndRewind(this.comparator(), afterSort.bind(this));
  5656. },
  5657.  
  5658. __proto__: WebInspector.DataGridNode.prototype
  5659. }
  5660.  
  5661.  
  5662.  
  5663. WebInspector.HeapSnapshotGenericObjectNode = function(tree, node)
  5664. {
  5665. this.snapshotNodeIndex = 0;
  5666. WebInspector.HeapSnapshotGridNode.call(this, tree, false);
  5667.  
  5668. if (!node)
  5669. return;
  5670. this._name = node.name;
  5671. this._type = node.type;
  5672. this._distanceToWindow = node.distanceToWindow;
  5673. this._shallowSize = node.selfSize;
  5674. this._retainedSize = node.retainedSize;
  5675. this.snapshotNodeId = node.id;
  5676. this.snapshotNodeIndex = node.nodeIndex;
  5677. if (this._type === "string")
  5678. this._reachableFromWindow = true;
  5679. else if (this._type === "object" && this.isWindow(this._name)) {
  5680. this._name = this.shortenWindowURL(this._name, false);
  5681. this._reachableFromWindow = true;
  5682. } else if (node.flags & tree.snapshot.nodeFlags.canBeQueried)
  5683. this._reachableFromWindow = true;
  5684. if (node.flags & tree.snapshot.nodeFlags.detachedDOMTreeNode)
  5685. this.detachedDOMTreeNode = true;
  5686. };
  5687.  
  5688. WebInspector.HeapSnapshotGenericObjectNode.prototype = {
  5689. createCell: function(columnIdentifier)
  5690. {
  5691. var cell = columnIdentifier !== "object" ? this._createValueCell(columnIdentifier) : this._createObjectCell();
  5692. if (this._searchMatched)
  5693. cell.addStyleClass("highlight");
  5694. return cell;
  5695. },
  5696.  
  5697. _createObjectCell: function()
  5698. {
  5699. var cell = document.createElement("td");
  5700. cell.className = "object-column";
  5701. var div = document.createElement("div");
  5702. div.className = "source-code event-properties";
  5703. div.style.overflow = "visible";
  5704. var data = this.data["object"];
  5705. if (this._prefixObjectCell)
  5706. this._prefixObjectCell(div, data);
  5707. var valueSpan = document.createElement("span");
  5708. valueSpan.className = "value console-formatted-" + data.valueStyle;
  5709. valueSpan.textContent = data.value;
  5710. div.appendChild(valueSpan);
  5711. var idSpan = document.createElement("span");
  5712. idSpan.className = "console-formatted-id";
  5713. idSpan.textContent = " @" + data["nodeId"];
  5714. div.appendChild(idSpan);
  5715. if (this._postfixObjectCell)
  5716. this._postfixObjectCell(div, data);
  5717. cell.appendChild(div);
  5718. cell.addStyleClass("disclosure");
  5719. if (this.depth)
  5720. cell.style.setProperty("padding-left", (this.depth * this.dataGrid.indentWidth) + "px");
  5721. cell.heapSnapshotNode = this;
  5722. return cell;
  5723. },
  5724.  
  5725. get data()
  5726. {
  5727. var data = this._emptyData();
  5728.  
  5729. var value = this._name;
  5730. var valueStyle = "object";
  5731. switch (this._type) {
  5732. case "string":
  5733. value = "\"" + value + "\"";
  5734. valueStyle = "string";
  5735. break;
  5736. case "regexp":
  5737. value = "/" + value + "/";
  5738. valueStyle = "string";
  5739. break;
  5740. case "closure":
  5741. value = "function" + (value ? " " : "") + value + "()";
  5742. valueStyle = "function";
  5743. break;
  5744. case "number":
  5745. valueStyle = "number";
  5746. break;
  5747. case "hidden":
  5748. valueStyle = "null";
  5749. break;
  5750. case "array":
  5751. if (!value)
  5752. value = "[]";
  5753. else
  5754. value += "[]";
  5755. break;
  5756. };
  5757. if (this._reachableFromWindow)
  5758. valueStyle += " highlight";
  5759. if (value === "Object")
  5760. value = "";
  5761. if (this.detachedDOMTreeNode)
  5762. valueStyle += " detached-dom-tree-node";
  5763. data["object"] = { valueStyle: valueStyle, value: value, nodeId: this.snapshotNodeId };
  5764.  
  5765. data["distanceToWindow"] =  this._distanceToWindow;
  5766. data["shallowSize"] = Number.withThousandsSeparator(this._shallowSize);
  5767. data["retainedSize"] = Number.withThousandsSeparator(this._retainedSize);
  5768. data["shallowSize-percent"] = this._toPercentString(this._shallowSizePercent);
  5769. data["retainedSize-percent"] = this._toPercentString(this._retainedSizePercent);
  5770.  
  5771. return this._enhanceData ? this._enhanceData(data) : data;
  5772. },
  5773.  
  5774. queryObjectContent: function(callback, objectGroupName)
  5775. {
  5776. if (this._type === "string")
  5777. callback(WebInspector.RemoteObject.fromPrimitiveValue(this._name));
  5778. else {
  5779. function formatResult(error, object)
  5780. {
  5781. if (!error && object.type)
  5782. callback(WebInspector.RemoteObject.fromPayload(object), !!error);
  5783. else
  5784. callback(WebInspector.RemoteObject.fromPrimitiveValue(WebInspector.UIString("Not available")));
  5785. }
  5786. ProfilerAgent.getObjectByHeapObjectId(String(this.snapshotNodeId), objectGroupName, formatResult);
  5787. }
  5788. },
  5789.  
  5790. get _retainedSizePercent()
  5791. {
  5792. return this._retainedSize / this.dataGrid.snapshot.totalSize * 100.0;
  5793. },
  5794.  
  5795. get _shallowSizePercent()
  5796. {
  5797. return this._shallowSize / this.dataGrid.snapshot.totalSize * 100.0;
  5798. },
  5799.  
  5800. updateHasChildren: function()
  5801. {
  5802. function isEmptyCallback(isEmpty)
  5803. {
  5804. this.hasChildren = !isEmpty;
  5805. }
  5806. this._provider().isEmpty(isEmptyCallback.bind(this));
  5807. },
  5808.  
  5809. isWindow: function(fullName)
  5810. {
  5811. return fullName.substr(0, 9) === "Window";
  5812. },
  5813.  
  5814. shortenWindowURL: function(fullName, hasObjectId)
  5815. {
  5816. var startPos = fullName.indexOf("/");
  5817. var endPos = hasObjectId ? fullName.indexOf("@") : fullName.length;
  5818. if (startPos !== -1 && endPos !== -1) {
  5819. var fullURL = fullName.substring(startPos + 1, endPos).trimLeft();
  5820. var url = fullURL.trimURL();
  5821. if (url.length > 40)
  5822. url = url.trimMiddle(40);
  5823. return fullName.substr(0, startPos + 2) + url + fullName.substr(endPos);
  5824. } else
  5825. return fullName;
  5826. },
  5827.  
  5828. __proto__: WebInspector.HeapSnapshotGridNode.prototype
  5829. }
  5830.  
  5831.  
  5832. WebInspector.HeapSnapshotObjectNode = function(tree, isFromBaseSnapshot, edge, parentGridNode)
  5833. {
  5834. WebInspector.HeapSnapshotGenericObjectNode.call(this, tree, edge.node);
  5835. this._referenceName = edge.name;
  5836. this._referenceType = edge.type;
  5837. this._propertyAccessor = edge.propertyAccessor;
  5838. this._distanceToWindow = edge.distanceToWindow;
  5839. this.showRetainingEdges = tree.showRetainingEdges;
  5840. this._isFromBaseSnapshot = isFromBaseSnapshot;
  5841.  
  5842. this._parentGridNode = parentGridNode;
  5843. this._cycledWithAncestorGridNode = this._findAncestorWithSameSnapshotNodeId();
  5844. if (!this._cycledWithAncestorGridNode)
  5845. this.updateHasChildren();
  5846. }
  5847.  
  5848. WebInspector.HeapSnapshotObjectNode.prototype = {
  5849.  
  5850. createProvider: function()
  5851. {
  5852. var tree = this._dataGrid;
  5853. var showHiddenData = WebInspector.settings.showHeapSnapshotObjectsHiddenProperties.get();
  5854. var filter = "function(edge) {\n" +
  5855. "    return !edge.isInvisible()\n" +
  5856. "        && (" + !tree.showRetainingEdges + " || (edge.node().id() !== 1 && !edge.node().isSynthetic() && !edge.isWeak()))\n" +
  5857. "        && (" + showHiddenData + " || (!edge.isHidden() && !edge.node().isHidden()));\n" +
  5858. "}\n";
  5859. var snapshot = this._isFromBaseSnapshot ? tree.baseSnapshot : tree.snapshot;
  5860. if (this.showRetainingEdges)
  5861. return snapshot.createRetainingEdgesProvider(this.snapshotNodeIndex, filter);
  5862. else
  5863. return snapshot.createEdgesProvider(this.snapshotNodeIndex, filter);
  5864. },
  5865.  
  5866. _findAncestorWithSameSnapshotNodeId: function()
  5867. {
  5868. var ancestor = this._parentGridNode;
  5869. while (ancestor) {
  5870. if (ancestor.snapshotNodeId === this.snapshotNodeId)
  5871. return ancestor;
  5872. ancestor = ancestor._parentGridNode;
  5873. }
  5874. return null;
  5875. },
  5876.  
  5877. _createChildNode: function(item)
  5878. {
  5879. return new WebInspector.HeapSnapshotObjectNode(this._dataGrid, this._isFromBaseSnapshot, item, this);
  5880. },
  5881.  
  5882. _childHashForEntity: function(edge)
  5883. {
  5884. var prefix = this.showRetainingEdges ? edge.node.id + "#" : "";
  5885. return prefix + edge.type + "#" + edge.name;
  5886. },
  5887.  
  5888. _childHashForNode: function(childNode)
  5889. {
  5890. var prefix = this.showRetainingEdges ? childNode.snapshotNodeId + "#" : "";
  5891. return prefix + childNode._referenceType + "#" + childNode._referenceName;
  5892. },
  5893.  
  5894. comparator: function()
  5895. {
  5896. var sortAscending = this._dataGrid.sortOrder === "ascending";
  5897. var sortColumnIdentifier = this._dataGrid.sortColumnIdentifier;
  5898. var sortFields = {
  5899. object: ["!edgeName", sortAscending, "retainedSize", false],
  5900. count: ["!edgeName", true, "retainedSize", false],
  5901. shallowSize: ["selfSize", sortAscending, "!edgeName", true],
  5902. retainedSize: ["retainedSize", sortAscending, "!edgeName", true],
  5903. distanceToWindow: ["distanceToWindow", sortAscending, "_name", true]
  5904. }[sortColumnIdentifier] || ["!edgeName", true, "retainedSize", false];
  5905. return WebInspector.HeapSnapshotFilteredOrderedIterator.prototype.createComparator(sortFields);
  5906. },
  5907.  
  5908. _emptyData: function()
  5909. {
  5910. return { count: "", addedCount: "", removedCount: "", countDelta: "", addedSize: "", removedSize: "", sizeDelta: "" };
  5911. },
  5912.  
  5913. _enhanceData: function(data)
  5914. {
  5915. var name = this._referenceName;
  5916. if (name === "") name = "(empty)";
  5917. var nameClass = "name";
  5918. switch (this._referenceType) {
  5919. case "context":
  5920. nameClass = "console-formatted-number";
  5921. break;
  5922. case "internal":
  5923. case "hidden":
  5924. nameClass = "console-formatted-null";
  5925. break;
  5926. case "element":
  5927. name = "[" + name + "]";
  5928. break;
  5929. }
  5930. data["object"].nameClass = nameClass;
  5931. data["object"].name = name;
  5932. data["distanceToWindow"] = this._distanceToWindow;
  5933. return data;
  5934. },
  5935.  
  5936. _prefixObjectCell: function(div, data)
  5937. {
  5938. if (this._cycledWithAncestorGridNode)
  5939. div.className += " cycled-ancessor-node";
  5940.  
  5941. var nameSpan = document.createElement("span");
  5942. nameSpan.className = data.nameClass;
  5943. nameSpan.textContent = data.name;
  5944. div.appendChild(nameSpan);
  5945.  
  5946. var separatorSpan = document.createElement("span");
  5947. separatorSpan.className = "grayed";
  5948. separatorSpan.textContent = this.showRetainingEdges ? " in " : " :: ";
  5949. div.appendChild(separatorSpan);
  5950. },
  5951.  
  5952. __proto__: WebInspector.HeapSnapshotGenericObjectNode.prototype
  5953. }
  5954.  
  5955.  
  5956. WebInspector.HeapSnapshotInstanceNode = function(tree, baseSnapshot, snapshot, node)
  5957. {
  5958. WebInspector.HeapSnapshotGenericObjectNode.call(this, tree, node);
  5959. this._baseSnapshotOrSnapshot = baseSnapshot || snapshot;
  5960. this._isDeletedNode = !!baseSnapshot;
  5961. this.updateHasChildren();
  5962. };
  5963.  
  5964. WebInspector.HeapSnapshotInstanceNode.prototype = {
  5965. createProvider: function()
  5966. {
  5967. var showHiddenData = WebInspector.settings.showHeapSnapshotObjectsHiddenProperties.get();
  5968. return this._baseSnapshotOrSnapshot.createEdgesProvider(
  5969. this.snapshotNodeIndex,
  5970. "function(edge) {" +
  5971. "    return !edge.isInvisible()" +
  5972. "        && (" + showHiddenData + " || (!edge.isHidden() && !edge.node().isHidden()));" +
  5973. "}");
  5974. },
  5975.  
  5976. _createChildNode: function(item)
  5977. {
  5978. return new WebInspector.HeapSnapshotObjectNode(this._dataGrid, this._isDeletedNode, item, null);
  5979. },
  5980.  
  5981. _childHashForEntity: function(edge)
  5982. {
  5983. return edge.type + "#" + edge.name;
  5984. },
  5985.  
  5986. _childHashForNode: function(childNode)
  5987. {
  5988. return childNode._referenceType + "#" + childNode._referenceName;
  5989. },
  5990.  
  5991. comparator: function()
  5992. {
  5993. var sortAscending = this._dataGrid.sortOrder === "ascending";
  5994. var sortColumnIdentifier = this._dataGrid.sortColumnIdentifier;
  5995. var sortFields = {
  5996. object: ["!edgeName", sortAscending, "retainedSize", false],
  5997. distanceToWindow: ["distanceToWindow", sortAscending, "retainedSize", false],
  5998. count: ["!edgeName", true, "retainedSize", false],
  5999. addedSize: ["selfSize", sortAscending, "!edgeName", true],
  6000. removedSize: ["selfSize", sortAscending, "!edgeName", true],
  6001. shallowSize: ["selfSize", sortAscending, "!edgeName", true],
  6002. retainedSize: ["retainedSize", sortAscending, "!edgeName", true]
  6003. }[sortColumnIdentifier] || ["!edgeName", true, "retainedSize", false];
  6004. return WebInspector.HeapSnapshotFilteredOrderedIterator.prototype.createComparator(sortFields);
  6005. },
  6006.  
  6007. _emptyData: function()
  6008. {
  6009. return {count:"", countDelta:"", sizeDelta: ""};
  6010. },
  6011.  
  6012. _enhanceData: function(data)
  6013. {
  6014. if (this._isDeletedNode) {
  6015. data["addedCount"] = "";
  6016. data["addedSize"] = "";
  6017. data["removedCount"] = "\u2022";
  6018. data["removedSize"] = Number.withThousandsSeparator(this._shallowSize);
  6019. } else {
  6020. data["addedCount"] = "\u2022";
  6021. data["addedSize"] = Number.withThousandsSeparator(this._shallowSize);
  6022. data["removedCount"] = "";
  6023. data["removedSize"] = "";
  6024. }
  6025. return data;
  6026. },
  6027.  
  6028. get isDeletedNode()
  6029. {
  6030. return this._isDeletedNode;
  6031. },
  6032.  
  6033. __proto__: WebInspector.HeapSnapshotGenericObjectNode.prototype
  6034. }
  6035.  
  6036.  
  6037. WebInspector.HeapSnapshotConstructorNode = function(tree, className, aggregate, aggregatesKey)
  6038. {
  6039. WebInspector.HeapSnapshotGridNode.call(this, tree, aggregate.count > 0);
  6040. this._name = className;
  6041. this._aggregatesKey = aggregatesKey;
  6042. this._distanceToWindow = aggregate.distanceToWindow;
  6043. this._count = aggregate.count;
  6044. this._shallowSize = aggregate.self;
  6045. this._retainedSize = aggregate.maxRet;
  6046. }
  6047.  
  6048. WebInspector.HeapSnapshotConstructorNode.prototype = {
  6049.  
  6050. createProvider: function()
  6051. {
  6052. return this._dataGrid.snapshot.createNodesProviderForClass(this._name, this._aggregatesKey)
  6053. },
  6054.  
  6055.  
  6056. revealNodeBySnapshotObjectId: function(snapshotObjectId)
  6057. {
  6058. function didExpand()
  6059. {
  6060. this._provider().nodePosition(snapshotObjectId, didGetNodePosition.bind(this));
  6061. }
  6062.  
  6063. function didGetNodePosition(nodePosition)
  6064. {
  6065. if (nodePosition === -1)
  6066. this.collapse();
  6067. else
  6068. this._populateChildren(nodePosition, null, didPopulateChildren.bind(this, nodePosition));
  6069. }
  6070.  
  6071. function didPopulateChildren(nodePosition)
  6072. {
  6073. var indexOfFirsChildInRange = 0;
  6074. for (var i = 0; i < this._retrievedChildrenRanges.length; i++) {
  6075. var range = this._retrievedChildrenRanges[i];
  6076. if (range.from <= nodePosition && nodePosition < range.to) {
  6077. var childIndex = indexOfFirsChildInRange + nodePosition - range.from;
  6078. var instanceNode = this.children[childIndex];
  6079. this._dataGrid.highlightNode(instanceNode);
  6080. return;
  6081. }
  6082. indexOfFirsChildInRange += range.to - range.from + 1;
  6083. }
  6084. }
  6085.  
  6086. this.expandWithoutPopulate(didExpand.bind(this));
  6087. },
  6088.  
  6089. createCell: function(columnIdentifier)
  6090. {
  6091. var cell = columnIdentifier !== "object" ? this._createValueCell(columnIdentifier) : WebInspector.HeapSnapshotGridNode.prototype.createCell.call(this, columnIdentifier);
  6092. if (this._searchMatched)
  6093. cell.addStyleClass("highlight");
  6094. return cell;
  6095. },
  6096.  
  6097. _createChildNode: function(item)
  6098. {
  6099. return new WebInspector.HeapSnapshotInstanceNode(this._dataGrid, null, this._dataGrid.snapshot, item);
  6100. },
  6101.  
  6102. comparator: function()
  6103. {
  6104. var sortAscending = this._dataGrid.sortOrder === "ascending";
  6105. var sortColumnIdentifier = this._dataGrid.sortColumnIdentifier;
  6106. var sortFields = {
  6107. object: ["id", sortAscending, "retainedSize", false],
  6108. distanceToWindow: ["distanceToWindow", true, "retainedSize", false],
  6109. count: ["id", true, "retainedSize", false],
  6110. shallowSize: ["selfSize", sortAscending, "id", true],
  6111. retainedSize: ["retainedSize", sortAscending, "id", true]
  6112. }[sortColumnIdentifier];
  6113. return WebInspector.HeapSnapshotFilteredOrderedIterator.prototype.createComparator(sortFields);
  6114. },
  6115.  
  6116. _childHashForEntity: function(node)
  6117. {
  6118. return node.id;
  6119. },
  6120.  
  6121. _childHashForNode: function(childNode)
  6122. {
  6123. return childNode.snapshotNodeId;
  6124. },
  6125.  
  6126. get data()
  6127. {
  6128. var data = { object: this._name };
  6129. data["count"] =  Number.withThousandsSeparator(this._count);
  6130. data["distanceToWindow"] =  this._distanceToWindow;
  6131. data["shallowSize"] = Number.withThousandsSeparator(this._shallowSize);
  6132. data["retainedSize"] = Number.withThousandsSeparator(this._retainedSize);
  6133. data["count-percent"] =  this._toPercentString(this._countPercent);
  6134. data["shallowSize-percent"] = this._toPercentString(this._shallowSizePercent);
  6135. data["retainedSize-percent"] = this._toPercentString(this._retainedSizePercent);
  6136. return data;
  6137. },
  6138.  
  6139. get _countPercent()
  6140. {
  6141. return this._count / this.dataGrid.snapshot.nodeCount * 100.0;
  6142. },
  6143.  
  6144. get _retainedSizePercent()
  6145. {
  6146. return this._retainedSize / this.dataGrid.snapshot.totalSize * 100.0;
  6147. },
  6148.  
  6149. get _shallowSizePercent()
  6150. {
  6151. return this._shallowSize / this.dataGrid.snapshot.totalSize * 100.0;
  6152. },
  6153.  
  6154. __proto__: WebInspector.HeapSnapshotGridNode.prototype
  6155. }
  6156.  
  6157.  
  6158.  
  6159. WebInspector.HeapSnapshotDiffNodesProvider = function(addedNodesProvider, deletedNodesProvider, addedCount, removedCount)
  6160. {
  6161. this._addedNodesProvider = addedNodesProvider;
  6162. this._deletedNodesProvider = deletedNodesProvider;
  6163. this._addedCount = addedCount;
  6164. this._removedCount = removedCount;
  6165. }
  6166.  
  6167. WebInspector.HeapSnapshotDiffNodesProvider.prototype = {
  6168. dispose: function()
  6169. {
  6170. this._addedNodesProvider.dispose();
  6171. this._deletedNodesProvider.dispose();
  6172. },
  6173.  
  6174. isEmpty: function(callback)
  6175. {
  6176. callback(false);
  6177. },
  6178.  
  6179. serializeItemsRange: function(beginPosition, endPosition, callback)
  6180. {
  6181. function didReceiveAllItems(items)
  6182. {
  6183. items.totalLength = this._addedCount + this._removedCount;
  6184. callback(items);
  6185. }
  6186.  
  6187. function didReceiveDeletedItems(addedItems, items)
  6188. {
  6189. if (!addedItems.length)
  6190. addedItems.startPosition = this._addedCount + items.startPosition;
  6191. for (var i = 0; i < items.length; i++) {
  6192. items[i].isAddedNotRemoved = false;
  6193. addedItems.push(items[i]);
  6194. }
  6195. addedItems.endPosition = this._addedCount + items.endPosition;
  6196. didReceiveAllItems.call(this, addedItems);
  6197. }
  6198.  
  6199. function didReceiveAddedItems(items)
  6200. {
  6201. for (var i = 0; i < items.length; i++)
  6202. items[i].isAddedNotRemoved = true;
  6203. if (items.endPosition < endPosition)
  6204. return this._deletedNodesProvider.serializeItemsRange(0, endPosition - items.endPosition, didReceiveDeletedItems.bind(this, items));
  6205.  
  6206. items.totalLength = this._addedCount + this._removedCount;
  6207. didReceiveAllItems.call(this, items);
  6208. }
  6209.  
  6210. if (beginPosition < this._addedCount)
  6211. this._addedNodesProvider.serializeItemsRange(beginPosition, endPosition, didReceiveAddedItems.bind(this));
  6212. else
  6213. this._deletedNodesProvider.serializeItemsRange(beginPosition - this._addedCount, endPosition - this._addedCount, didReceiveDeletedItems.bind(this, []));
  6214. },
  6215.  
  6216. sortAndRewind: function(comparator, callback)
  6217. {
  6218. function afterSort()
  6219. {
  6220. this._deletedNodesProvider.sortAndRewind(comparator, callback);
  6221. }
  6222. this._addedNodesProvider.sortAndRewind(comparator, afterSort.bind(this));
  6223. }
  6224. };
  6225.  
  6226.  
  6227. WebInspector.HeapSnapshotDiffNode = function(tree, className, diffForClass)
  6228. {
  6229. WebInspector.HeapSnapshotGridNode.call(this, tree, true);
  6230. this._name = className;
  6231.  
  6232. this._addedCount = diffForClass.addedCount;
  6233. this._removedCount = diffForClass.removedCount;
  6234. this._countDelta = diffForClass.countDelta;
  6235. this._addedSize = diffForClass.addedSize;
  6236. this._removedSize = diffForClass.removedSize;
  6237. this._sizeDelta = diffForClass.sizeDelta;
  6238. this._deletedIndexes = diffForClass.deletedIndexes;
  6239. }
  6240.  
  6241. WebInspector.HeapSnapshotDiffNode.prototype = {
  6242.  
  6243. createProvider: function()
  6244. {
  6245. var tree = this._dataGrid;
  6246. return  new WebInspector.HeapSnapshotDiffNodesProvider(
  6247. tree.snapshot.createAddedNodesProvider(tree.baseSnapshot.uid, this._name),
  6248. tree.baseSnapshot.createDeletedNodesProvider(this._deletedIndexes),
  6249. this._addedCount,
  6250. this._removedCount);
  6251. },
  6252.  
  6253. _createChildNode: function(item)
  6254. {
  6255. if (item.isAddedNotRemoved)
  6256. return new WebInspector.HeapSnapshotInstanceNode(this._dataGrid, null, this._dataGrid.snapshot, item);
  6257. else
  6258. return new WebInspector.HeapSnapshotInstanceNode(this._dataGrid, this._dataGrid.baseSnapshot, null, item);
  6259. },
  6260.  
  6261. _childHashForEntity: function(node)
  6262. {
  6263. return node.id;
  6264. },
  6265.  
  6266. _childHashForNode: function(childNode)
  6267. {
  6268. return childNode.snapshotNodeId;
  6269. },
  6270.  
  6271. comparator: function()
  6272. {
  6273. var sortAscending = this._dataGrid.sortOrder === "ascending";
  6274. var sortColumnIdentifier = this._dataGrid.sortColumnIdentifier;
  6275. var sortFields = {
  6276. object: ["id", sortAscending, "selfSize", false],
  6277. addedCount: ["selfSize", sortAscending, "id", true],
  6278. removedCount: ["selfSize", sortAscending, "id", true],
  6279. countDelta: ["selfSize", sortAscending, "id", true],
  6280. addedSize: ["selfSize", sortAscending, "id", true],
  6281. removedSize: ["selfSize", sortAscending, "id", true],
  6282. sizeDelta: ["selfSize", sortAscending, "id", true]
  6283. }[sortColumnIdentifier];
  6284. return WebInspector.HeapSnapshotFilteredOrderedIterator.prototype.createComparator(sortFields);
  6285. },
  6286.  
  6287. _signForDelta: function(delta)
  6288. {
  6289. if (delta === 0)
  6290. return "";
  6291. if (delta > 0)
  6292. return "+";
  6293. else
  6294. return "\u2212";  
  6295. },
  6296.  
  6297. get data()
  6298. {
  6299. var data = {object: this._name};
  6300.  
  6301. data["addedCount"] = Number.withThousandsSeparator(this._addedCount);
  6302. data["removedCount"] = Number.withThousandsSeparator(this._removedCount);
  6303. data["countDelta"] = this._signForDelta(this._countDelta) + Number.withThousandsSeparator(Math.abs(this._countDelta));
  6304. data["addedSize"] = Number.withThousandsSeparator(this._addedSize);
  6305. data["removedSize"] = Number.withThousandsSeparator(this._removedSize);
  6306. data["sizeDelta"] = this._signForDelta(this._sizeDelta) + Number.withThousandsSeparator(Math.abs(this._sizeDelta));
  6307.  
  6308. return data;
  6309. },
  6310.  
  6311. __proto__: WebInspector.HeapSnapshotGridNode.prototype
  6312. }
  6313.  
  6314.  
  6315.  
  6316. WebInspector.HeapSnapshotDominatorObjectNode = function(tree, node)
  6317. {
  6318. WebInspector.HeapSnapshotGenericObjectNode.call(this, tree, node);
  6319. this.updateHasChildren();
  6320. };
  6321.  
  6322. WebInspector.HeapSnapshotDominatorObjectNode.prototype = {
  6323.  
  6324. createProvider: function()
  6325. {
  6326. return this._dataGrid.snapshot.createNodesProviderForDominator(this.snapshotNodeIndex);
  6327. },
  6328.  
  6329.  
  6330. retrieveChildBySnapshotObjectId: function(snapshotObjectId, callback)
  6331. {
  6332. function didExpand()
  6333. {
  6334. this._provider().nodePosition(snapshotObjectId, didGetNodePosition.bind(this));
  6335. }
  6336.  
  6337. function didGetNodePosition(nodePosition)
  6338. {
  6339. if (nodePosition === -1) {
  6340. this.collapse();
  6341. callback(null);
  6342. } else
  6343. this._populateChildren(nodePosition, null, didPopulateChildren.bind(this, nodePosition));
  6344. }
  6345.  
  6346. function didPopulateChildren(nodePosition)
  6347. {
  6348. var child = this.childForPosition(nodePosition);
  6349. callback(child);
  6350. }
  6351.  
  6352.  
  6353.  
  6354. this.hasChildren = true;
  6355. this.expandWithoutPopulate(didExpand.bind(this));
  6356. },
  6357.  
  6358. _createChildNode: function(item)
  6359. {
  6360. return new WebInspector.HeapSnapshotDominatorObjectNode(this._dataGrid, item);
  6361. },
  6362.  
  6363. _childHashForEntity: function(node)
  6364. {
  6365. return node.id;
  6366. },
  6367.  
  6368. _childHashForNode: function(childNode)
  6369. {
  6370. return childNode.snapshotNodeId;
  6371. },
  6372.  
  6373. comparator: function()
  6374. {
  6375. var sortAscending = this._dataGrid.sortOrder === "ascending";
  6376. var sortColumnIdentifier = this._dataGrid.sortColumnIdentifier;
  6377. var sortFields = {
  6378. object: ["id", sortAscending, "retainedSize", false],
  6379. shallowSize: ["selfSize", sortAscending, "id", true],
  6380. retainedSize: ["retainedSize", sortAscending, "id", true]
  6381. }[sortColumnIdentifier];
  6382. return WebInspector.HeapSnapshotFilteredOrderedIterator.prototype.createComparator(sortFields);
  6383. },
  6384.  
  6385. _emptyData: function()
  6386. {
  6387. return {};
  6388. },
  6389.  
  6390. __proto__: WebInspector.HeapSnapshotGenericObjectNode.prototype
  6391. }
  6392.  
  6393. ;
  6394.  
  6395.  
  6396.  
  6397. WebInspector.HeapSnapshotLoader = function()
  6398. {
  6399. this._reset();
  6400. }
  6401.  
  6402. WebInspector.HeapSnapshotLoader.prototype = {
  6403. dispose: function()
  6404. {
  6405. this._reset();
  6406. },
  6407.  
  6408. _reset: function()
  6409. {
  6410. this._json = "";
  6411. this._state = "find-snapshot-info";
  6412. this._snapshot = {};
  6413. },
  6414.  
  6415. close: function()
  6416. {
  6417. if (this._json)
  6418. this._parseStringsArray();
  6419. },
  6420.  
  6421. buildSnapshot: function()
  6422. {
  6423. var result = new WebInspector.HeapSnapshot(this._snapshot);
  6424. this._reset();
  6425. return result;
  6426. },
  6427.  
  6428. _parseUintArray: function()
  6429. {
  6430. var index = 0;
  6431. var char0 = "0".charCodeAt(0), char9 = "9".charCodeAt(0), closingBracket = "]".charCodeAt(0);
  6432. var length = this._json.length;
  6433. while (true) {
  6434. while (index < length) {
  6435. var code = this._json.charCodeAt(index);
  6436. if (char0 <= code && code <= char9)
  6437. break;
  6438. else if (code === closingBracket) {
  6439. this._json = this._json.slice(index + 1);
  6440. return false;
  6441. }
  6442. ++index;
  6443. }
  6444. if (index === length) {
  6445. this._json = "";
  6446. return true;
  6447. }
  6448. var nextNumber = 0;
  6449. var startIndex = index;
  6450. while (index < length) {
  6451. var code = this._json.charCodeAt(index);
  6452. if (char0 > code || code > char9)
  6453. break;
  6454. nextNumber *= 10;
  6455. nextNumber += (code - char0);
  6456. ++index;
  6457. }
  6458. if (index === length) {
  6459. this._json = this._json.slice(startIndex);
  6460. return true;
  6461. }
  6462. this._array[this._arrayIndex++] = nextNumber;
  6463. }
  6464. },
  6465.  
  6466. _parseStringsArray: function()
  6467. {
  6468. var closingBracketIndex = this._json.lastIndexOf("]");
  6469. if (closingBracketIndex === -1)
  6470. throw new Error("Incomplete JSON");
  6471. this._json = this._json.slice(0, closingBracketIndex + 1);
  6472. this._snapshot.strings = JSON.parse(this._json);
  6473. },
  6474.  
  6475.  
  6476. write: function(chunk)
  6477. {
  6478. this._json += chunk;
  6479. switch (this._state) {
  6480. case "find-snapshot-info": {
  6481. var snapshotToken = "\"snapshot\"";
  6482. var snapshotTokenIndex = this._json.indexOf(snapshotToken);
  6483. if (snapshotTokenIndex === -1)
  6484. throw new Error("Snapshot token not found");
  6485. this._json = this._json.slice(snapshotTokenIndex + snapshotToken.length + 1);
  6486. this._state = "parse-snapshot-info";
  6487. }
  6488. case "parse-snapshot-info": {
  6489. var closingBracketIndex = WebInspector.findBalancedCurlyBrackets(this._json);
  6490. if (closingBracketIndex === -1)
  6491. return;
  6492. this._snapshot.snapshot =   (JSON.parse(this._json.slice(0, closingBracketIndex)));
  6493. this._json = this._json.slice(closingBracketIndex);
  6494. this._state = "find-nodes";
  6495. }
  6496. case "find-nodes": {
  6497. var nodesToken = "\"nodes\"";
  6498. var nodesTokenIndex = this._json.indexOf(nodesToken);
  6499. if (nodesTokenIndex === -1)
  6500. return;
  6501. var bracketIndex = this._json.indexOf("[", nodesTokenIndex);
  6502. if (bracketIndex === -1)
  6503. return;
  6504. this._json = this._json.slice(bracketIndex + 1);
  6505. var node_fields_count = this._snapshot.snapshot.meta.node_fields.length;
  6506. var nodes_length = this._snapshot.snapshot.node_count * node_fields_count;
  6507. this._array = new Uint32Array(nodes_length);
  6508. this._arrayIndex = 0;
  6509. this._state = "parse-nodes";
  6510. }
  6511. case "parse-nodes": {
  6512. if (this._parseUintArray())
  6513. return;
  6514. this._snapshot.nodes = this._array;
  6515. this._state = "find-edges";
  6516. this._array = null;
  6517. }
  6518. case "find-edges": {
  6519. var edgesToken = "\"edges\"";
  6520. var edgesTokenIndex = this._json.indexOf(edgesToken);
  6521. if (edgesTokenIndex === -1)
  6522. return;
  6523. var bracketIndex = this._json.indexOf("[", edgesTokenIndex);
  6524. if (bracketIndex === -1)
  6525. return;
  6526. this._json = this._json.slice(bracketIndex + 1);
  6527. var edge_fields_count = this._snapshot.snapshot.meta.edge_fields.length;
  6528. var edges_length = this._snapshot.snapshot.edge_count * edge_fields_count;
  6529. this._array = new Uint32Array(edges_length);
  6530. this._arrayIndex = 0;
  6531. this._state = "parse-edges";
  6532. }
  6533. case "parse-edges": {
  6534. if (this._parseUintArray())
  6535. return;
  6536. this._snapshot.edges = this._array;
  6537. this._array = null;
  6538. this._state = "find-strings";
  6539. }
  6540. case "find-strings": {
  6541. var stringsToken = "\"strings\"";
  6542. var stringsTokenIndex = this._json.indexOf(stringsToken);
  6543. if (stringsTokenIndex === -1)
  6544. return;
  6545. var bracketIndex = this._json.indexOf("[", stringsTokenIndex);
  6546. if (bracketIndex === -1)
  6547. return;
  6548. this._json = this._json.slice(bracketIndex);
  6549. this._state = "accumulate-strings";
  6550. break;
  6551. }
  6552. case "accumulate-strings":
  6553. break;
  6554. }
  6555. }
  6556. };
  6557. ;
  6558.  
  6559.  
  6560.  
  6561. WebInspector.HeapSnapshotWorkerWrapper = function()
  6562. {
  6563. }
  6564.  
  6565. WebInspector.HeapSnapshotWorkerWrapper.prototype =  {
  6566. postMessage: function(message)
  6567. {
  6568. },
  6569. terminate: function()
  6570. {
  6571. },
  6572.  
  6573. __proto__: WebInspector.Object.prototype
  6574. }
  6575.  
  6576.  
  6577. WebInspector.HeapSnapshotRealWorker = function()
  6578. {
  6579. this._worker = new Worker("HeapSnapshotWorker.js");
  6580. this._worker.addEventListener("message", this._messageReceived.bind(this), false);
  6581. }
  6582.  
  6583. WebInspector.HeapSnapshotRealWorker.prototype = {
  6584. _messageReceived: function(event)
  6585. {
  6586. var message = event.data;
  6587. if ("callId" in message)
  6588. this.dispatchEventToListeners("message", message);
  6589. else {
  6590. if (message.object !== "console") {
  6591. console.log(WebInspector.UIString("Worker asks to call a method '%s' on an unsupported object '%s'.", message.method, message.object));
  6592. return;
  6593. }
  6594. if (message.method !== "log" && message.method !== "info" && message.method !== "error") {
  6595. console.log(WebInspector.UIString("Worker asks to call an unsupported method '%s' on the console object.", message.method));
  6596. return;
  6597. }
  6598. console[message.method].apply(window[message.object], message.arguments);
  6599. }
  6600. },
  6601.  
  6602. postMessage: function(message)
  6603. {
  6604. this._worker.postMessage(message);
  6605. },
  6606.  
  6607. terminate: function()
  6608. {
  6609. this._worker.terminate();
  6610. },
  6611.  
  6612. __proto__: WebInspector.HeapSnapshotWorkerWrapper.prototype
  6613. }
  6614.  
  6615.  
  6616.  
  6617. WebInspector.AsyncTaskQueue = function()
  6618. {
  6619. this._queue = [];
  6620. this._isTimerSheduled = false;
  6621. }
  6622.  
  6623. WebInspector.AsyncTaskQueue.prototype = {
  6624.  
  6625. addTask: function(task)
  6626. {
  6627. this._queue.push(task);
  6628. this._scheduleTimer();
  6629. },
  6630.  
  6631. _onTimeout: function()
  6632. {
  6633. this._isTimerSheduled = false;
  6634. var queue = this._queue;
  6635. this._queue = [];
  6636. for (var i = 0; i < queue.length; i++) {
  6637. try {
  6638. queue[i]();
  6639. } catch (e) {
  6640. console.error("Exception while running task: " + e.stack);
  6641. }
  6642. }
  6643. this._scheduleTimer();
  6644. },
  6645.  
  6646. _scheduleTimer: function()
  6647. {
  6648. if (this._queue.length && !this._isTimerSheduled) {
  6649. setTimeout(this._onTimeout.bind(this), 0);
  6650. this._isTimerSheduled = true;
  6651. }
  6652. }
  6653. }
  6654.  
  6655.  
  6656. WebInspector.HeapSnapshotFakeWorker = function()
  6657. {
  6658. this._dispatcher = new WebInspector.HeapSnapshotWorkerDispatcher(window, this._postMessageFromWorker.bind(this));
  6659. this._asyncTaskQueue = new WebInspector.AsyncTaskQueue();
  6660. }
  6661.  
  6662. WebInspector.HeapSnapshotFakeWorker.prototype = {
  6663. postMessage: function(message)
  6664. {
  6665. function dispatch()
  6666. {
  6667. if (this._dispatcher)
  6668. this._dispatcher.dispatchMessage({data: message});
  6669. }
  6670. this._asyncTaskQueue.addTask(dispatch.bind(this));
  6671. },
  6672.  
  6673. terminate: function()
  6674. {
  6675. this._dispatcher = null;
  6676. },
  6677.  
  6678. _postMessageFromWorker: function(message)
  6679. {
  6680. function send()
  6681. {
  6682. this.dispatchEventToListeners("message", message);
  6683. }
  6684. this._asyncTaskQueue.addTask(send.bind(this));
  6685. },
  6686.  
  6687. __proto__: WebInspector.HeapSnapshotWorkerWrapper.prototype
  6688. }
  6689.  
  6690.  
  6691.  
  6692. WebInspector.HeapSnapshotWorker = function()
  6693. {
  6694. this._nextObjectId = 1;
  6695. this._nextCallId = 1;
  6696. this._callbacks = [];
  6697. this._previousCallbacks = [];
  6698.  
  6699. this._worker = typeof InspectorTest === "undefined" ? new WebInspector.HeapSnapshotRealWorker() : new WebInspector.HeapSnapshotFakeWorker();
  6700. this._worker.addEventListener("message", this._messageReceived, this);
  6701. }
  6702.  
  6703. WebInspector.HeapSnapshotWorker.prototype = {
  6704. createObject: function(constructorName)
  6705. {
  6706. var proxyConstructorFunction = this._findFunction(constructorName + "Proxy");
  6707. var objectId = this._nextObjectId++;
  6708. var proxy = new proxyConstructorFunction(this, objectId);
  6709. this._postMessage({callId: this._nextCallId++, disposition: "create", objectId: objectId, methodName: constructorName});
  6710. return proxy;
  6711. },
  6712.  
  6713. dispose: function()
  6714. {
  6715. this._worker.terminate();
  6716. if (this._interval)
  6717. clearInterval(this._interval);
  6718. },
  6719.  
  6720. disposeObject: function(objectId)
  6721. {
  6722. this._postMessage({callId: this._nextCallId++, disposition: "dispose", objectId: objectId});
  6723. },
  6724.  
  6725. callGetter: function(callback, objectId, getterName)
  6726. {
  6727. var callId = this._nextCallId++;
  6728. this._callbacks[callId] = callback;
  6729. this._postMessage({callId: callId, disposition: "getter", objectId: objectId, methodName: getterName});
  6730. },
  6731.  
  6732. callFactoryMethod: function(callback, objectId, methodName, proxyConstructorName)
  6733. {
  6734. var callId = this._nextCallId++;
  6735. var methodArguments = Array.prototype.slice.call(arguments, 4);
  6736. var newObjectId = this._nextObjectId++;
  6737. var proxyConstructorFunction = this._findFunction(proxyConstructorName);
  6738. if (callback) {
  6739. function wrapCallback(remoteResult)
  6740. {
  6741. callback(remoteResult ? new proxyConstructorFunction(this, newObjectId) : null);
  6742. }
  6743. this._callbacks[callId] = wrapCallback.bind(this);
  6744. this._postMessage({callId: callId, disposition: "factory", objectId: objectId, methodName: methodName, methodArguments: methodArguments, newObjectId: newObjectId});
  6745. return null;
  6746. } else {
  6747. this._postMessage({callId: callId, disposition: "factory", objectId: objectId, methodName: methodName, methodArguments: methodArguments, newObjectId: newObjectId});
  6748. return new proxyConstructorFunction(this, newObjectId);
  6749. }
  6750. },
  6751.  
  6752. callMethod: function(callback, objectId, methodName)
  6753. {
  6754. var callId = this._nextCallId++;
  6755. var methodArguments = Array.prototype.slice.call(arguments, 3);
  6756. if (callback)
  6757. this._callbacks[callId] = callback;
  6758. this._postMessage({callId: callId, disposition: "method", objectId: objectId, methodName: methodName, methodArguments: methodArguments});
  6759. },
  6760.  
  6761. startCheckingForLongRunningCalls: function()
  6762. {
  6763. if (this._interval)
  6764. return;
  6765. this._checkLongRunningCalls();
  6766. this._interval = setInterval(this._checkLongRunningCalls.bind(this), 300);
  6767. },
  6768.  
  6769. _checkLongRunningCalls: function()
  6770. {
  6771. for (var callId in this._previousCallbacks)
  6772. if (!(callId in this._callbacks))
  6773. delete this._previousCallbacks[callId];
  6774. var hasLongRunningCalls = false;
  6775. for (callId in this._previousCallbacks) {
  6776. hasLongRunningCalls = true;
  6777. break;
  6778. }
  6779. this.dispatchEventToListeners("wait", hasLongRunningCalls);
  6780. for (callId in this._callbacks)
  6781. this._previousCallbacks[callId] = true;
  6782. },
  6783.  
  6784. _findFunction: function(name)
  6785. {
  6786. var path = name.split(".");
  6787. var result = window;
  6788. for (var i = 0; i < path.length; ++i)
  6789. result = result[path[i]];
  6790. return result;
  6791. },
  6792.  
  6793. _messageReceived: function(event)
  6794. {
  6795. var data = event.data;
  6796. if (event.data.error) {
  6797. if (event.data.errorMethodName)
  6798. WebInspector.log(WebInspector.UIString("An error happened when a call for method '%s' was requested", event.data.errorMethodName));
  6799. WebInspector.log(event.data.errorCallStack);
  6800. delete this._callbacks[data.callId];
  6801. return;
  6802. }
  6803. if (!this._callbacks[data.callId])
  6804. return;
  6805. var callback = this._callbacks[data.callId];
  6806. delete this._callbacks[data.callId];
  6807. callback(data.result);
  6808. },
  6809.  
  6810. _postMessage: function(message)
  6811. {
  6812. this._worker.postMessage(message);
  6813. },
  6814.  
  6815. __proto__: WebInspector.Object.prototype
  6816. }
  6817.  
  6818.  
  6819.  
  6820. WebInspector.HeapSnapshotProxyObject = function(worker, objectId)
  6821. {
  6822. this._worker = worker;
  6823. this._objectId = objectId;
  6824. }
  6825.  
  6826. WebInspector.HeapSnapshotProxyObject.prototype = {
  6827. _callWorker: function(workerMethodName, args)
  6828. {
  6829. args.splice(1, 0, this._objectId);
  6830. return this._worker[workerMethodName].apply(this._worker, args);
  6831. },
  6832.  
  6833. dispose: function()
  6834. {
  6835. this._worker.disposeObject(this._objectId);
  6836. },
  6837.  
  6838. disposeWorker: function()
  6839. {
  6840. this._worker.dispose();
  6841. },
  6842.  
  6843.  
  6844. callFactoryMethod: function(callback, methodName, proxyConstructorName, var_args)
  6845. {
  6846. return this._callWorker("callFactoryMethod", Array.prototype.slice.call(arguments, 0));
  6847. },
  6848.  
  6849. callGetter: function(callback, getterName)
  6850. {
  6851. return this._callWorker("callGetter", Array.prototype.slice.call(arguments, 0));
  6852. },
  6853.  
  6854.  
  6855. callMethod: function(callback, methodName, var_args)
  6856. {
  6857. return this._callWorker("callMethod", Array.prototype.slice.call(arguments, 0));
  6858. },
  6859.  
  6860. get worker() {
  6861. return this._worker;
  6862. }
  6863. };
  6864.  
  6865.  
  6866. WebInspector.HeapSnapshotLoaderProxy = function(worker, objectId)
  6867. {
  6868. WebInspector.HeapSnapshotProxyObject.call(this, worker, objectId);
  6869. this._pendingSnapshotConsumers = [];
  6870. }
  6871.  
  6872. WebInspector.HeapSnapshotLoaderProxy.prototype = {
  6873.  
  6874. addConsumer: function(callback)
  6875. {
  6876. this._pendingSnapshotConsumers.push(callback);
  6877. },
  6878.  
  6879.  
  6880. write: function(chunk, callback)
  6881. {
  6882. this.callMethod(callback, "write", chunk);
  6883. },
  6884.  
  6885. close: function()
  6886. {
  6887. function buildSnapshot()
  6888. {
  6889. this.callFactoryMethod(updateStaticData.bind(this), "buildSnapshot", "WebInspector.HeapSnapshotProxy");
  6890. }
  6891. function updateStaticData(snapshotProxy)
  6892. {
  6893. this.dispose();
  6894. snapshotProxy.updateStaticData(notifyPendingConsumers.bind(this));
  6895. }
  6896. function notifyPendingConsumers(snapshotProxy)
  6897. {
  6898. for (var i = 0; i < this._pendingSnapshotConsumers.length; ++i)
  6899. this._pendingSnapshotConsumers[i](snapshotProxy);
  6900. this._pendingSnapshotConsumers = [];
  6901. }
  6902. this.callMethod(buildSnapshot.bind(this), "close");
  6903. },
  6904.  
  6905. __proto__: WebInspector.HeapSnapshotProxyObject.prototype
  6906. }
  6907.  
  6908.  
  6909.  
  6910. WebInspector.HeapSnapshotProxy = function(worker, objectId)
  6911. {
  6912. WebInspector.HeapSnapshotProxyObject.call(this, worker, objectId);
  6913. }
  6914.  
  6915. WebInspector.HeapSnapshotProxy.prototype = {
  6916. aggregates: function(sortedIndexes, key, filter, callback)
  6917. {
  6918. this.callMethod(callback, "aggregates", sortedIndexes, key, filter);
  6919. },
  6920.  
  6921. aggregatesForDiff: function(callback)
  6922. {
  6923. this.callMethod(callback, "aggregatesForDiff");
  6924. },
  6925.  
  6926. calculateSnapshotDiff: function(baseSnapshotId, baseSnapshotAggregates, callback)
  6927. {
  6928. this.callMethod(callback, "calculateSnapshotDiff", baseSnapshotId, baseSnapshotAggregates);
  6929. },
  6930.  
  6931. nodeClassName: function(snapshotObjectId, callback)
  6932. {
  6933. this.callMethod(callback, "nodeClassName", snapshotObjectId);
  6934. },
  6935.  
  6936. dominatorIdsForNode: function(nodeIndex, callback)
  6937. {
  6938. this.callMethod(callback, "dominatorIdsForNode", nodeIndex);
  6939. },
  6940.  
  6941. createEdgesProvider: function(nodeIndex, filter)
  6942. {
  6943. return this.callFactoryMethod(null, "createEdgesProvider", "WebInspector.HeapSnapshotProviderProxy", nodeIndex, filter);
  6944. },
  6945.  
  6946. createRetainingEdgesProvider: function(nodeIndex, filter)
  6947. {
  6948. return this.callFactoryMethod(null, "createRetainingEdgesProvider", "WebInspector.HeapSnapshotProviderProxy", nodeIndex, filter);
  6949. },
  6950.  
  6951. createAddedNodesProvider: function(baseSnapshotId, className)
  6952. {
  6953. return this.callFactoryMethod(null, "createAddedNodesProvider", "WebInspector.HeapSnapshotProviderProxy", baseSnapshotId, className);
  6954. },
  6955.  
  6956. createDeletedNodesProvider: function(nodeIndexes)
  6957. {
  6958. return this.callFactoryMethod(null, "createDeletedNodesProvider", "WebInspector.HeapSnapshotProviderProxy", nodeIndexes);
  6959. },
  6960.  
  6961. createNodesProvider: function(filter)
  6962. {
  6963. return this.callFactoryMethod(null, "createNodesProvider", "WebInspector.HeapSnapshotProviderProxy", filter);
  6964. },
  6965.  
  6966. createNodesProviderForClass: function(className, aggregatesKey)
  6967. {
  6968. return this.callFactoryMethod(null, "createNodesProviderForClass", "WebInspector.HeapSnapshotProviderProxy", className, aggregatesKey);
  6969. },
  6970.  
  6971. createNodesProviderForDominator: function(nodeIndex)
  6972. {
  6973. return this.callFactoryMethod(null, "createNodesProviderForDominator", "WebInspector.HeapSnapshotProviderProxy", nodeIndex);
  6974. },
  6975.  
  6976. dispose: function()
  6977. {
  6978. this.disposeWorker();
  6979. },
  6980.  
  6981. get nodeCount()
  6982. {
  6983. return this._staticData.nodeCount;
  6984. },
  6985.  
  6986. get nodeFlags()
  6987. {
  6988. return this._staticData.nodeFlags;
  6989. },
  6990.  
  6991. get rootNodeIndex()
  6992. {
  6993. return this._staticData.rootNodeIndex;
  6994. },
  6995.  
  6996. updateStaticData: function(callback)
  6997. {
  6998. function dataReceived(staticData)
  6999. {
  7000. this._staticData = staticData;
  7001. callback(this);
  7002. }
  7003. this.callMethod(dataReceived.bind(this), "updateStaticData");
  7004. },
  7005.  
  7006. get totalSize()
  7007. {
  7008. return this._staticData.totalSize;
  7009. },
  7010.  
  7011. get uid()
  7012. {
  7013. return this._staticData.uid;
  7014. },
  7015.  
  7016. __proto__: WebInspector.HeapSnapshotProxyObject.prototype
  7017. }
  7018.  
  7019.  
  7020.  
  7021. WebInspector.HeapSnapshotProviderProxy = function(worker, objectId)
  7022. {
  7023. WebInspector.HeapSnapshotProxyObject.call(this, worker, objectId);
  7024. }
  7025.  
  7026. WebInspector.HeapSnapshotProviderProxy.prototype = {
  7027. nodePosition: function(snapshotObjectId, callback)
  7028. {
  7029. this.callMethod(callback, "nodePosition", snapshotObjectId);
  7030. },
  7031.  
  7032. isEmpty: function(callback)
  7033. {
  7034. this.callMethod(callback, "isEmpty");
  7035. },
  7036.  
  7037. serializeItemsRange: function(startPosition, endPosition, callback)
  7038. {
  7039. this.callMethod(callback, "serializeItemsRange", startPosition, endPosition);
  7040. },
  7041.  
  7042. sortAndRewind: function(comparator, callback)
  7043. {
  7044. this.callMethod(callback, "sortAndRewind", comparator);
  7045. },
  7046.  
  7047. __proto__: WebInspector.HeapSnapshotProxyObject.prototype
  7048. }
  7049.  
  7050. ;
  7051.  
  7052.  
  7053.  
  7054. WebInspector.HeapSnapshotView = function(parent, profile)
  7055. {
  7056. WebInspector.View.call(this);
  7057.  
  7058. this.element.addStyleClass("heap-snapshot-view");
  7059.  
  7060. this.parent = parent;
  7061. this.parent.addEventListener("profile added", this._updateBaseOptions, this);
  7062. this.parent.addEventListener("profile added", this._updateFilterOptions, this);
  7063.  
  7064. this.viewsContainer = document.createElement("div");
  7065. this.viewsContainer.addStyleClass("views-container");
  7066. this.element.appendChild(this.viewsContainer);
  7067.  
  7068. this.containmentView = new WebInspector.View();
  7069. this.containmentView.element.addStyleClass("view");
  7070. this.containmentDataGrid = new WebInspector.HeapSnapshotContainmentDataGrid();
  7071. this.containmentDataGrid.element.addEventListener("mousedown", this._mouseDownInContentsGrid.bind(this), true);
  7072. this.containmentDataGrid.show(this.containmentView.element);
  7073. this.containmentDataGrid.addEventListener(WebInspector.DataGrid.Events.SelectedNode, this._selectionChanged, this);
  7074.  
  7075. this.constructorsView = new WebInspector.View();
  7076. this.constructorsView.element.addStyleClass("view");
  7077. this.constructorsView.element.appendChild(this._createToolbarWithClassNameFilter());
  7078.  
  7079. this.constructorsDataGrid = new WebInspector.HeapSnapshotConstructorsDataGrid();
  7080. this.constructorsDataGrid.element.addStyleClass("class-view-grid");
  7081. this.constructorsDataGrid.element.addEventListener("mousedown", this._mouseDownInContentsGrid.bind(this), true);
  7082. this.constructorsDataGrid.show(this.constructorsView.element);
  7083. this.constructorsDataGrid.addEventListener(WebInspector.DataGrid.Events.SelectedNode, this._selectionChanged, this);
  7084.  
  7085. this.diffView = new WebInspector.View();
  7086. this.diffView.element.addStyleClass("view");
  7087. this.diffView.element.appendChild(this._createToolbarWithClassNameFilter());
  7088.  
  7089. this.diffDataGrid = new WebInspector.HeapSnapshotDiffDataGrid();
  7090. this.diffDataGrid.element.addStyleClass("class-view-grid");
  7091. this.diffDataGrid.show(this.diffView.element);
  7092. this.diffDataGrid.addEventListener(WebInspector.DataGrid.Events.SelectedNode, this._selectionChanged, this);
  7093.  
  7094. this.dominatorView = new WebInspector.View();
  7095. this.dominatorView.element.addStyleClass("view");
  7096. this.dominatorDataGrid = new WebInspector.HeapSnapshotDominatorsDataGrid();
  7097. this.dominatorDataGrid.element.addEventListener("mousedown", this._mouseDownInContentsGrid.bind(this), true);
  7098. this.dominatorDataGrid.show(this.dominatorView.element);
  7099. this.dominatorDataGrid.addEventListener(WebInspector.DataGrid.Events.SelectedNode, this._selectionChanged, this);
  7100.  
  7101. this.retainmentViewHeader = document.createElement("div");
  7102. this.retainmentViewHeader.addStyleClass("retainers-view-header");
  7103. WebInspector.installDragHandle(this.retainmentViewHeader, this._startRetainersHeaderDragging.bind(this), this._retainersHeaderDragging.bind(this), this._endRetainersHeaderDragging.bind(this), "row-resize");
  7104. var retainingPathsTitleDiv = document.createElement("div");
  7105. retainingPathsTitleDiv.className = "title";
  7106. var retainingPathsTitle = document.createElement("span");
  7107. retainingPathsTitle.textContent = WebInspector.UIString("Object's retaining tree");
  7108. retainingPathsTitleDiv.appendChild(retainingPathsTitle);
  7109. this.retainmentViewHeader.appendChild(retainingPathsTitleDiv);
  7110. this.element.appendChild(this.retainmentViewHeader);
  7111.  
  7112. this.retainmentView = new WebInspector.View();
  7113. this.retainmentView.element.addStyleClass("view");
  7114. this.retainmentView.element.addStyleClass("retaining-paths-view");
  7115. this.retainmentDataGrid = new WebInspector.HeapSnapshotRetainmentDataGrid();
  7116. this.retainmentDataGrid.show(this.retainmentView.element);
  7117. this.retainmentDataGrid.addEventListener(WebInspector.DataGrid.Events.SelectedNode, this._inspectedObjectChanged, this);
  7118. this.retainmentView.show(this.element);
  7119. this.retainmentDataGrid.reset();
  7120.  
  7121. this.dataGrid = this.constructorsDataGrid;
  7122. this.currentView = this.constructorsView;
  7123.  
  7124. this.viewSelectElement = document.createElement("select");
  7125. this.viewSelectElement.className = "status-bar-item";
  7126. this.viewSelectElement.addEventListener("change", this._onSelectedViewChanged.bind(this), false);
  7127.  
  7128. this.views = [{title: "Summary", view: this.constructorsView, grid: this.constructorsDataGrid},
  7129. {title: "Comparison", view: this.diffView, grid: this.diffDataGrid},
  7130. {title: "Containment", view: this.containmentView, grid: this.containmentDataGrid},
  7131. {title: "Dominators", view: this.dominatorView, grid: this.dominatorDataGrid}];
  7132. this.views.current = 0;
  7133. for (var i = 0; i < this.views.length; ++i) {
  7134. var view = this.views[i];
  7135. var option = document.createElement("option");
  7136. option.label = WebInspector.UIString(view.title);
  7137. this.viewSelectElement.appendChild(option);
  7138. }
  7139.  
  7140. this._profileUid = profile.uid;
  7141.  
  7142. this.baseSelectElement = document.createElement("select");
  7143. this.baseSelectElement.className = "status-bar-item";
  7144. this.baseSelectElement.addEventListener("change", this._changeBase.bind(this), false);
  7145. this._updateBaseOptions();
  7146.  
  7147. this.filterSelectElement = document.createElement("select");
  7148. this.filterSelectElement.className = "status-bar-item";
  7149. this.filterSelectElement.addEventListener("change", this._changeFilter.bind(this), false);
  7150. this._updateFilterOptions();
  7151.  
  7152. this.helpButton = new WebInspector.StatusBarButton("", "heap-snapshot-help-status-bar-item status-bar-item");
  7153. this.helpButton.addEventListener("click", this._helpClicked, this);
  7154.  
  7155. this._popoverHelper = new WebInspector.ObjectPopoverHelper(this.element, this._getHoverAnchor.bind(this), this._resolveObjectForPopover.bind(this), undefined, true);
  7156.  
  7157. this.profile.load(profileCallback.bind(this));
  7158.  
  7159. function profileCallback(heapSnapshotProxy)
  7160. {
  7161. var list = this._profiles();
  7162. var profileIndex;
  7163. for (var i = 0; i < list.length; ++i) {
  7164. if (list[i].uid === this._profileUid) {
  7165. profileIndex = i;
  7166. break;
  7167. }
  7168. }
  7169.  
  7170. if (profileIndex > 0)
  7171. this.baseSelectElement.selectedIndex = profileIndex - 1;
  7172. else
  7173. this.baseSelectElement.selectedIndex = profileIndex;
  7174. this.dataGrid.setDataSource(heapSnapshotProxy);
  7175. }
  7176. }
  7177.  
  7178. WebInspector.HeapSnapshotView.prototype = {
  7179. dispose: function()
  7180. {
  7181. this.profile.dispose();
  7182. if (this.baseProfile)
  7183. this.baseProfile.dispose();
  7184. this.containmentDataGrid.dispose();
  7185. this.constructorsDataGrid.dispose();
  7186. this.diffDataGrid.dispose();
  7187. this.dominatorDataGrid.dispose();
  7188. this.retainmentDataGrid.dispose();
  7189. },
  7190.  
  7191. get statusBarItems()
  7192. {
  7193.  
  7194. function appendArrowImage(element, hidden)
  7195. {
  7196. var span = document.createElement("span");
  7197. span.className = "status-bar-select-container" + (hidden ? " hidden" : "");
  7198. span.appendChild(element);
  7199. return span;
  7200. }
  7201. return [appendArrowImage(this.viewSelectElement), appendArrowImage(this.baseSelectElement, true), appendArrowImage(this.filterSelectElement), this.helpButton.element];
  7202. },
  7203.  
  7204. get profile()
  7205. {
  7206. return this.parent.getProfile(WebInspector.HeapSnapshotProfileType.TypeId, this._profileUid);
  7207. },
  7208.  
  7209. get baseProfile()
  7210. {
  7211. return this.parent.getProfile(WebInspector.HeapSnapshotProfileType.TypeId, this._baseProfileUid);
  7212. },
  7213.  
  7214. wasShown: function()
  7215. {
  7216.  
  7217. this.profile.load(profileCallback1.bind(this));
  7218.  
  7219. function profileCallback1() {
  7220. if (this.baseProfile)
  7221. this.baseProfile.load(profileCallback2.bind(this));
  7222. else
  7223. profileCallback2.call(this);
  7224. }
  7225.  
  7226. function profileCallback2() {
  7227. this.currentView.show(this.viewsContainer);
  7228. }
  7229. },
  7230.  
  7231. willHide: function()
  7232. {
  7233. this._currentSearchResultIndex = -1;
  7234. this._popoverHelper.hidePopover();
  7235. if (this.helpPopover && this.helpPopover.isShowing())
  7236. this.helpPopover.hide();
  7237. },
  7238.  
  7239. onResize: function()
  7240. {
  7241. var height = this.retainmentView.element.clientHeight;
  7242. this._updateRetainmentViewHeight(height);
  7243. },
  7244.  
  7245. searchCanceled: function()
  7246. {
  7247. if (this._searchResults) {
  7248. for (var i = 0; i < this._searchResults.length; ++i) {
  7249. var node = this._searchResults[i].node;
  7250. delete node._searchMatched;
  7251. node.refresh();
  7252. }
  7253. }
  7254.  
  7255. delete this._searchFinishedCallback;
  7256. this._currentSearchResultIndex = -1;
  7257. this._searchResults = [];
  7258. },
  7259.  
  7260. performSearch: function(query, finishedCallback)
  7261. {
  7262.  
  7263. this.searchCanceled();
  7264.  
  7265. query = query.trim();
  7266.  
  7267. if (!query.length)
  7268. return;
  7269. if (this.currentView !== this.constructorsView && this.currentView !== this.diffView)
  7270. return;
  7271.  
  7272. this._searchFinishedCallback = finishedCallback;
  7273.  
  7274. function matchesByName(gridNode) {
  7275. return ("_name" in gridNode) && gridNode._name.hasSubstring(query, true);
  7276. }
  7277.  
  7278. function matchesById(gridNode) {
  7279. return ("snapshotNodeId" in gridNode) && gridNode.snapshotNodeId === query;
  7280. }
  7281.  
  7282. var matchPredicate;
  7283. if (query.charAt(0) !== "@")
  7284. matchPredicate = matchesByName;
  7285. else {
  7286. query = parseInt(query.substring(1), 10);
  7287. matchPredicate = matchesById;
  7288. }
  7289.  
  7290. function matchesQuery(gridNode)
  7291. {
  7292. delete gridNode._searchMatched;
  7293. if (matchPredicate(gridNode)) {
  7294. gridNode._searchMatched = true;
  7295. gridNode.refresh();
  7296. return true;
  7297. }
  7298. return false;
  7299. }
  7300.  
  7301. var current = this.dataGrid.rootNode().children[0];
  7302. var depth = 0;
  7303. var info = {};
  7304.  
  7305.  
  7306. const maxDepth = 1;
  7307.  
  7308. while (current) {
  7309. if (matchesQuery(current))
  7310. this._searchResults.push({ node: current });
  7311. current = current.traverseNextNode(false, null, (depth >= maxDepth), info);
  7312. depth += info.depthChange;
  7313. }
  7314.  
  7315. finishedCallback(this, this._searchResults.length);
  7316. },
  7317.  
  7318. jumpToFirstSearchResult: function()
  7319. {
  7320. if (!this._searchResults || !this._searchResults.length)
  7321. return;
  7322. this._currentSearchResultIndex = 0;
  7323. this._jumpToSearchResult(this._currentSearchResultIndex);
  7324. },
  7325.  
  7326. jumpToLastSearchResult: function()
  7327. {
  7328. if (!this._searchResults || !this._searchResults.length)
  7329. return;
  7330. this._currentSearchResultIndex = (this._searchResults.length - 1);
  7331. this._jumpToSearchResult(this._currentSearchResultIndex);
  7332. },
  7333.  
  7334. jumpToNextSearchResult: function()
  7335. {
  7336. if (!this._searchResults || !this._searchResults.length)
  7337. return;
  7338. if (++this._currentSearchResultIndex >= this._searchResults.length)
  7339. this._currentSearchResultIndex = 0;
  7340. this._jumpToSearchResult(this._currentSearchResultIndex);
  7341. },
  7342.  
  7343. jumpToPreviousSearchResult: function()
  7344. {
  7345. if (!this._searchResults || !this._searchResults.length)
  7346. return;
  7347. if (--this._currentSearchResultIndex < 0)
  7348. this._currentSearchResultIndex = (this._searchResults.length - 1);
  7349. this._jumpToSearchResult(this._currentSearchResultIndex);
  7350. },
  7351.  
  7352. showingFirstSearchResult: function()
  7353. {
  7354. return (this._currentSearchResultIndex === 0);
  7355. },
  7356.  
  7357. showingLastSearchResult: function()
  7358. {
  7359. return (this._searchResults && this._currentSearchResultIndex === (this._searchResults.length - 1));
  7360. },
  7361.  
  7362. _jumpToSearchResult: function(index)
  7363. {
  7364. var searchResult = this._searchResults[index];
  7365. if (!searchResult)
  7366. return;
  7367.  
  7368. var node = searchResult.node;
  7369. node.revealAndSelect();
  7370. },
  7371.  
  7372. refreshVisibleData: function()
  7373. {
  7374. var child = this.dataGrid.rootNode().children[0];
  7375. while (child) {
  7376. child.refresh();
  7377. child = child.traverseNextNode(false, null, true);
  7378. }
  7379. },
  7380.  
  7381. _changeBase: function()
  7382. {
  7383. if (this._baseProfileUid === this._profiles()[this.baseSelectElement.selectedIndex].uid)
  7384. return;
  7385.  
  7386. this._baseProfileUid = this._profiles()[this.baseSelectElement.selectedIndex].uid;
  7387. var dataGrid =   (this.dataGrid);
  7388.  
  7389. if (dataGrid.snapshot)
  7390. this.baseProfile.load(dataGrid.setBaseDataSource.bind(dataGrid));
  7391.  
  7392. if (!this.currentQuery || !this._searchFinishedCallback || !this._searchResults)
  7393. return;
  7394.  
  7395.  
  7396.  
  7397.  
  7398. this._searchFinishedCallback(this, -this._searchResults.length);
  7399. this.performSearch(this.currentQuery, this._searchFinishedCallback);
  7400. },
  7401.  
  7402. _changeFilter: function()
  7403. {
  7404. var profileIndex = this.filterSelectElement.selectedIndex - 1;
  7405. this.dataGrid.filterSelectIndexChanged(this._profiles(), profileIndex);
  7406.  
  7407. WebInspector.notifications.dispatchEventToListeners(WebInspector.UserMetrics.UserAction, {
  7408. action: WebInspector.UserMetrics.UserActionNames.HeapSnapshotFilterChanged,
  7409. label: this.filterSelectElement[this.filterSelectElement.selectedIndex].label
  7410. });
  7411.  
  7412. if (!this.currentQuery || !this._searchFinishedCallback || !this._searchResults)
  7413. return;
  7414.  
  7415.  
  7416.  
  7417.  
  7418. this._searchFinishedCallback(this, -this._searchResults.length);
  7419. this.performSearch(this.currentQuery, this._searchFinishedCallback);
  7420. },
  7421.  
  7422. _createToolbarWithClassNameFilter: function()
  7423. {
  7424. var toolbar = document.createElement("div");
  7425. toolbar.addStyleClass("class-view-toolbar");
  7426. var classNameFilter = document.createElement("input");
  7427. classNameFilter.addStyleClass("class-name-filter");
  7428. classNameFilter.setAttribute("placeholder", WebInspector.UIString("Class filter"));
  7429. classNameFilter.addEventListener("keyup", this._changeNameFilter.bind(this, classNameFilter), false);
  7430. toolbar.appendChild(classNameFilter);
  7431. return toolbar;
  7432. },
  7433.  
  7434. _changeNameFilter: function(classNameInputElement)
  7435. {
  7436. var filter = classNameInputElement.value;
  7437. this.dataGrid.changeNameFilter(filter);
  7438. },
  7439.  
  7440.  
  7441. _profiles: function()
  7442. {
  7443. return this.parent.getProfiles(WebInspector.HeapSnapshotProfileType.TypeId);
  7444. },
  7445.  
  7446. processLoadedSnapshot: function(profile, snapshot)
  7447. {
  7448. profile.nodes = snapshot.nodes;
  7449. profile.strings = snapshot.strings;
  7450. var s = new WebInspector.HeapSnapshot(profile);
  7451. profile.sidebarElement.subtitle = Number.bytesToString(s.totalSize);
  7452. },
  7453.  
  7454.  
  7455. populateContextMenu: function(contextMenu, event)
  7456. {
  7457. this.dataGrid.populateContextMenu(this.parent, contextMenu, event);
  7458. },
  7459.  
  7460. _selectionChanged: function(event)
  7461. {
  7462. var selectedNode = event.target.selectedNode;
  7463. this._setRetainmentDataGridSource(selectedNode);
  7464. this._inspectedObjectChanged(event);
  7465. },
  7466.  
  7467. _inspectedObjectChanged: function(event)
  7468. {
  7469. var selectedNode = event.target.selectedNode;
  7470. if (!this.profile.fromFile() && selectedNode instanceof WebInspector.HeapSnapshotGenericObjectNode)
  7471. ConsoleAgent.addInspectedHeapObject(selectedNode.snapshotNodeId);
  7472. },
  7473.  
  7474. _setRetainmentDataGridSource: function(nodeItem)
  7475. {
  7476. if (nodeItem && nodeItem.snapshotNodeIndex)
  7477. this.retainmentDataGrid.setDataSource(nodeItem.isDeletedNode ? nodeItem.dataGrid.baseSnapshot : nodeItem.dataGrid.snapshot, nodeItem.snapshotNodeIndex);
  7478. else
  7479. this.retainmentDataGrid.reset();
  7480. },
  7481.  
  7482. _mouseDownInContentsGrid: function(event)
  7483. {
  7484. if (event.detail < 2)
  7485. return;
  7486.  
  7487. var cell = event.target.enclosingNodeOrSelfWithNodeName("td");
  7488. if (!cell || (!cell.hasStyleClass("count-column") && !cell.hasStyleClass("shallowSize-column") && !cell.hasStyleClass("retainedSize-column")))
  7489. return;
  7490.  
  7491. event.consume(true);
  7492. },
  7493.  
  7494. changeView: function(viewTitle, callback)
  7495. {
  7496. var viewIndex = null;
  7497. for (var i = 0; i < this.views.length; ++i)
  7498. if (this.views[i].title === viewTitle) {
  7499. viewIndex = i;
  7500. break;
  7501. }
  7502. if (this.views.current === viewIndex) {
  7503. setTimeout(callback, 0);
  7504. return;
  7505. }
  7506.  
  7507. function dataGridContentShown(event)
  7508. {
  7509. var dataGrid = event.data;
  7510. dataGrid.removeEventListener(WebInspector.HeapSnapshotSortableDataGrid.Events.ContentShown, dataGridContentShown, this);
  7511. if (dataGrid === this.dataGrid)
  7512. callback();
  7513. }
  7514. this.views[viewIndex].grid.addEventListener(WebInspector.HeapSnapshotSortableDataGrid.Events.ContentShown, dataGridContentShown, this);
  7515.  
  7516. this.viewSelectElement.selectedIndex = viewIndex;
  7517. this._changeView(viewIndex);
  7518. },
  7519.  
  7520. _updateDataSourceAndView: function()
  7521. {
  7522. var dataGrid = this.dataGrid;
  7523. if (dataGrid.snapshot)
  7524. return;
  7525.  
  7526. this.profile.load(didLoadSnapshot.bind(this));
  7527. function didLoadSnapshot(snapshotProxy)
  7528. {
  7529. if (this.dataGrid !== dataGrid)
  7530. return;
  7531. if (dataGrid.snapshot !== snapshotProxy)
  7532. dataGrid.setDataSource(snapshotProxy);
  7533. if (dataGrid === this.diffDataGrid) {
  7534. if (!this._baseProfileUid)
  7535. this._baseProfileUid = this._profiles()[this.baseSelectElement.selectedIndex].uid;
  7536. this.baseProfile.load(didLoadBaseSnaphot.bind(this));
  7537. }
  7538. }
  7539.  
  7540. function didLoadBaseSnaphot(baseSnapshotProxy)
  7541. {
  7542. if (this.diffDataGrid.baseSnapshot !== baseSnapshotProxy)
  7543. this.diffDataGrid.setBaseDataSource(baseSnapshotProxy);
  7544. }
  7545. },
  7546.  
  7547. _onSelectedViewChanged: function(event)
  7548. {
  7549. this._changeView(event.target.selectedIndex);
  7550. },
  7551.  
  7552. _updateSelectorsVisibility: function()
  7553. {
  7554. if (this.currentView === this.diffView)
  7555. this.baseSelectElement.parentElement.removeStyleClass("hidden");
  7556. else
  7557. this.baseSelectElement.parentElement.addStyleClass("hidden");
  7558.  
  7559. if (this.currentView === this.constructorsView)
  7560. this.filterSelectElement.parentElement.removeStyleClass("hidden");
  7561. else
  7562. this.filterSelectElement.parentElement.addStyleClass("hidden");
  7563. },
  7564.  
  7565. _changeView: function(selectedIndex)
  7566. {
  7567. if (selectedIndex === this.views.current)
  7568. return;
  7569.  
  7570. this.views.current = selectedIndex;
  7571. this.currentView.detach();
  7572. var view = this.views[this.views.current];
  7573. this.currentView = view.view;
  7574. this.dataGrid = view.grid;
  7575. this.currentView.show(this.viewsContainer);
  7576. this.refreshVisibleData();
  7577. this.dataGrid.updateWidths();
  7578.  
  7579. this._updateSelectorsVisibility();
  7580.  
  7581. this._updateDataSourceAndView();
  7582.  
  7583. if (!this.currentQuery || !this._searchFinishedCallback || !this._searchResults)
  7584. return;
  7585.  
  7586.  
  7587.  
  7588.  
  7589. this._searchFinishedCallback(this, -this._searchResults.length);
  7590. this.performSearch(this.currentQuery, this._searchFinishedCallback);
  7591. },
  7592.  
  7593. _getHoverAnchor: function(target)
  7594. {
  7595. var span = target.enclosingNodeOrSelfWithNodeName("span");
  7596. if (!span)
  7597. return;
  7598. var row = target.enclosingNodeOrSelfWithNodeName("tr");
  7599. if (!row)
  7600. return;
  7601. span.node = row._dataGridNode;
  7602. return span;
  7603. },
  7604.  
  7605. _resolveObjectForPopover: function(element, showCallback, objectGroupName)
  7606. {
  7607. if (this.profile.fromFile())
  7608. return;
  7609. element.node.queryObjectContent(showCallback, objectGroupName);
  7610. },
  7611.  
  7612. _helpClicked: function(event)
  7613. {
  7614. if (!this._helpPopoverContentElement) {
  7615. var refTypes = ["a:", "console-formatted-name", WebInspector.UIString("property"),
  7616. "0:", "console-formatted-name", WebInspector.UIString("element"),
  7617. "a:", "console-formatted-number", WebInspector.UIString("context var"),
  7618. "a:", "console-formatted-null", WebInspector.UIString("system prop")];
  7619. var objTypes = [" a ", "console-formatted-object", "Object",
  7620. "\"a\"", "console-formatted-string", "String",
  7621. "/a/", "console-formatted-string", "RegExp",
  7622. "a()", "console-formatted-function", "Function",
  7623. "a[]", "console-formatted-object", "Array",
  7624. "num", "console-formatted-number", "Number",
  7625. " a ", "console-formatted-null", "System"];
  7626.  
  7627. var contentElement = document.createElement("table");
  7628. contentElement.className = "heap-snapshot-help";
  7629. var headerRow = document.createElement("tr");
  7630. var propsHeader = document.createElement("th");
  7631. propsHeader.textContent = WebInspector.UIString("Property types:");
  7632. headerRow.appendChild(propsHeader);
  7633. var objsHeader = document.createElement("th");
  7634. objsHeader.textContent = WebInspector.UIString("Object types:");
  7635. headerRow.appendChild(objsHeader);
  7636. contentElement.appendChild(headerRow);
  7637.  
  7638. function appendHelp(help, index, cell)
  7639. {
  7640. var div = document.createElement("div");
  7641. div.className = "source-code event-properties";
  7642. var name = document.createElement("span");
  7643. name.textContent = help[index];
  7644. name.className = help[index + 1];
  7645. div.appendChild(name);
  7646. var desc = document.createElement("span");
  7647. desc.textContent = " " + help[index + 2];
  7648. div.appendChild(desc);
  7649. cell.appendChild(div);
  7650. }
  7651.  
  7652. var len = Math.max(refTypes.length, objTypes.length);
  7653. for (var i = 0; i < len; i += 3) {
  7654. var row = document.createElement("tr");
  7655. var refCell = document.createElement("td");
  7656. if (refTypes[i])
  7657. appendHelp(refTypes, i, refCell);
  7658. row.appendChild(refCell);
  7659. var objCell = document.createElement("td");
  7660. if (objTypes[i])
  7661. appendHelp(objTypes, i, objCell);
  7662. row.appendChild(objCell);
  7663. contentElement.appendChild(row);
  7664. }
  7665. this._helpPopoverContentElement = contentElement;
  7666. this.helpPopover = new WebInspector.Popover();
  7667. }
  7668. if (this.helpPopover.isShowing())
  7669. this.helpPopover.hide();
  7670. else
  7671. this.helpPopover.show(this._helpPopoverContentElement, this.helpButton.element);
  7672. },
  7673.  
  7674.  
  7675. _startRetainersHeaderDragging: function(event)
  7676. {
  7677. if (!this.isShowing())
  7678. return false;
  7679.  
  7680. this._previousDragPosition = event.pageY;
  7681. return true;
  7682. },
  7683.  
  7684. _retainersHeaderDragging: function(event)
  7685. {
  7686. var height = this.retainmentView.element.clientHeight;
  7687. height += this._previousDragPosition - event.pageY;
  7688. this._previousDragPosition = event.pageY;
  7689. this._updateRetainmentViewHeight(height);
  7690. event.consume(true);
  7691. },
  7692.  
  7693. _endRetainersHeaderDragging: function(event)
  7694. {
  7695. delete this._previousDragPosition;
  7696. event.consume();
  7697. },
  7698.  
  7699. _updateRetainmentViewHeight: function(height)
  7700. {
  7701. height = Number.constrain(height, Preferences.minConsoleHeight, this.element.clientHeight - Preferences.minConsoleHeight);
  7702. this.viewsContainer.style.bottom = (height + this.retainmentViewHeader.clientHeight) + "px";
  7703. this.retainmentView.element.style.height = height + "px";
  7704. this.retainmentViewHeader.style.bottom = height + "px";
  7705. },
  7706.  
  7707. _updateBaseOptions: function()
  7708. {
  7709. var list = this._profiles();
  7710.  
  7711. if (this.baseSelectElement.length === list.length)
  7712. return;
  7713.  
  7714. for (var i = this.baseSelectElement.length, n = list.length; i < n; ++i) {
  7715. var baseOption = document.createElement("option");
  7716. var title = list[i].title;
  7717. if (!title.indexOf(UserInitiatedProfileName))
  7718. title = WebInspector.UIString("Snapshot %d", title.substring(UserInitiatedProfileName.length + 1));
  7719. baseOption.label = title;
  7720. this.baseSelectElement.appendChild(baseOption);
  7721. }
  7722. },
  7723.  
  7724. _updateFilterOptions: function()
  7725. {
  7726. var list = this._profiles();
  7727.  
  7728. if (this.filterSelectElement.length - 1 === list.length)
  7729. return;
  7730.  
  7731. if (!this.filterSelectElement.length) {
  7732. var filterOption = document.createElement("option");
  7733. filterOption.label = WebInspector.UIString("All objects");
  7734. this.filterSelectElement.appendChild(filterOption);
  7735. }
  7736.  
  7737. if (this.profile.fromFile())
  7738. return;
  7739. for (var i = this.filterSelectElement.length - 1, n = list.length; i < n; ++i) {
  7740. var profile = list[i];
  7741. var filterOption = document.createElement("option");
  7742. var title = list[i].title;
  7743. if (!title.indexOf(UserInitiatedProfileName)) {
  7744. if (!i)
  7745. title = WebInspector.UIString("Objects allocated before Snapshot %d", title.substring(UserInitiatedProfileName.length + 1));
  7746. else
  7747. title = WebInspector.UIString("Objects allocated between Snapshots %d and %d", title.substring(UserInitiatedProfileName.length + 1) - 1, title.substring(UserInitiatedProfileName.length + 1));
  7748. }
  7749. filterOption.label = title;
  7750. this.filterSelectElement.appendChild(filterOption);
  7751. }
  7752. },
  7753.  
  7754. __proto__: WebInspector.View.prototype
  7755. }
  7756.  
  7757.  
  7758.  
  7759. WebInspector.HeapSnapshotProfileType = function()
  7760. {
  7761. WebInspector.ProfileType.call(this, WebInspector.HeapSnapshotProfileType.TypeId, WebInspector.UIString("Take Heap Snapshot"));
  7762. }
  7763.  
  7764. WebInspector.HeapSnapshotProfileType.TypeId = "HEAP";
  7765.  
  7766. WebInspector.HeapSnapshotProfileType.prototype = {
  7767. get buttonTooltip()
  7768. {
  7769. return WebInspector.UIString("Take heap snapshot.");
  7770. },
  7771.  
  7772.  
  7773. buttonClicked: function(profilesPanel)
  7774. {
  7775. profilesPanel.takeHeapSnapshot();
  7776. return false;
  7777. },
  7778.  
  7779. get treeItemTitle()
  7780. {
  7781. return WebInspector.UIString("HEAP SNAPSHOTS");
  7782. },
  7783.  
  7784. get description()
  7785. {
  7786. return WebInspector.UIString("Heap snapshot profiles show memory distribution among your page's JavaScript objects and related DOM nodes.");
  7787. },
  7788.  
  7789.  
  7790. createTemporaryProfile: function(title)
  7791. {
  7792. title = title || WebInspector.UIString("Snapshotting\u2026");
  7793. return new WebInspector.HeapProfileHeader(this, title);
  7794. },
  7795.  
  7796.  
  7797. createProfile: function(profile)
  7798. {
  7799. return new WebInspector.HeapProfileHeader(this, profile.title, profile.uid, profile.maxJSObjectId || 0);
  7800. },
  7801.  
  7802. __proto__: WebInspector.ProfileType.prototype
  7803. }
  7804.  
  7805.  
  7806. WebInspector.HeapProfileHeader = function(type, title, uid, maxJSObjectId)
  7807. {
  7808. WebInspector.ProfileHeader.call(this, type, title, uid);
  7809. this.maxJSObjectId = maxJSObjectId;
  7810.  
  7811. this._receiver = null;
  7812.  
  7813. this._snapshotProxy = null;
  7814. this._totalNumberOfChunks = 0;
  7815. }
  7816.  
  7817. WebInspector.HeapProfileHeader.prototype = {
  7818.  
  7819. createSidebarTreeElement: function()
  7820. {
  7821. return new WebInspector.ProfileSidebarTreeElement(this, WebInspector.UIString("Snapshot %d"), "heap-snapshot-sidebar-tree-item");
  7822. },
  7823.  
  7824.  
  7825. createView: function(profilesPanel)
  7826. {
  7827. return new WebInspector.HeapSnapshotView(profilesPanel, this);
  7828. },
  7829.  
  7830. snapshotProxy: function()
  7831. {
  7832. return this._snapshotProxy;
  7833. },
  7834.  
  7835.  
  7836. load: function(callback)
  7837. {
  7838. if (this._snapshotProxy) {
  7839. callback(this._snapshotProxy);
  7840. return;
  7841. }
  7842.  
  7843. this._numberOfChunks = 0;
  7844. this._savedChunks = 0;
  7845. this._savingToFile = false;
  7846. if (!this._receiver) {
  7847. this._setupWorker();
  7848. this.sidebarElement.subtitle = WebInspector.UIString("Loading\u2026");
  7849. this.sidebarElement.wait = true;
  7850. ProfilerAgent.getProfile(this.profileType().id, this.uid);
  7851. }
  7852. var loaderProxy =   (this._receiver);
  7853. loaderProxy.addConsumer(callback);
  7854. },
  7855.  
  7856. _setupWorker: function()
  7857. {
  7858. function setProfileWait(event)
  7859. {
  7860. this.sidebarElement.wait = event.data;
  7861. }
  7862. var worker = new WebInspector.HeapSnapshotWorker();
  7863. worker.addEventListener("wait", setProfileWait, this);
  7864. var loaderProxy = worker.createObject("WebInspector.HeapSnapshotLoader");
  7865. loaderProxy.addConsumer(this._snapshotReceived.bind(this));
  7866. this._receiver = loaderProxy;
  7867. },
  7868.  
  7869. dispose: function()
  7870. {
  7871. if (this._receiver)
  7872. this._receiver.close();
  7873. else if (this._snapshotProxy)
  7874. this._snapshotProxy.dispose();
  7875. },
  7876.  
  7877.  
  7878. _updateTransferProgress: function(value, maxValue)
  7879. {
  7880. var percentValue = ((maxValue ? (value / maxValue) : 0) * 100).toFixed(2);
  7881. if (this._savingToFile)
  7882. this.sidebarElement.subtitle = WebInspector.UIString("Saving\u2026 %d\%", percentValue);
  7883. else
  7884. this.sidebarElement.subtitle = WebInspector.UIString("Loading\u2026 %d\%", percentValue);
  7885. },
  7886.  
  7887. _updateSnapshotStatus: function()
  7888. {
  7889. this.sidebarElement.subtitle = Number.bytesToString(this._snapshotProxy.totalSize);
  7890. this.sidebarElement.wait = false;
  7891. },
  7892.  
  7893.  
  7894. transferChunk: function(chunk)
  7895. {
  7896. ++this._numberOfChunks;
  7897. this._receiver.write(chunk, callback.bind(this));
  7898. function callback()
  7899. {
  7900. this._updateTransferProgress(++this._savedChunks, this._totalNumberOfChunks);
  7901. if (this._totalNumberOfChunks === this._savedChunks) {
  7902. if (this._savingToFile)
  7903. this._updateSnapshotStatus();
  7904. else
  7905. this.sidebarElement.subtitle = WebInspector.UIString("Parsing\u2026");
  7906.  
  7907. this._receiver.close();
  7908. }
  7909. }
  7910. },
  7911.  
  7912. _snapshotReceived: function(snapshotProxy)
  7913. {
  7914. this._receiver = null;
  7915. if (snapshotProxy)
  7916. this._snapshotProxy = snapshotProxy;
  7917. this._updateSnapshotStatus();
  7918. var worker =   (this._snapshotProxy.worker);
  7919. this.isTemporary = false;
  7920. worker.startCheckingForLongRunningCalls();
  7921. },
  7922.  
  7923. finishHeapSnapshot: function()
  7924. {
  7925. this._totalNumberOfChunks = this._numberOfChunks;
  7926. },
  7927.  
  7928.  
  7929. canSaveToFile: function()
  7930. {
  7931. return !this.fromFile() && !!this._snapshotProxy && !this._receiver;
  7932. },
  7933.  
  7934.  
  7935. saveToFile: function()
  7936. {
  7937. this._numberOfChunks = 0;
  7938.  
  7939. var fileOutputStream = new WebInspector.FileOutputStream();
  7940. function onOpen()
  7941. {
  7942. this._receiver = fileOutputStream;
  7943. this._savedChunks = 0;
  7944. this._updateTransferProgress(0, this._totalNumberOfChunks);
  7945. ProfilerAgent.getProfile(this.profileType().id, this.uid);
  7946. }
  7947. this._savingToFile = true;
  7948. this._fileName = this._fileName || "Heap-" + new Date().toISO8601Compact() + ".heapsnapshot";
  7949. fileOutputStream.open(this._fileName, onOpen.bind(this));
  7950. },
  7951.  
  7952.  
  7953. canLoadFromFile: function()
  7954. {
  7955. return false;
  7956. },
  7957.  
  7958.  
  7959. loadFromFile: function(file)
  7960. {
  7961. this.title = file.name;
  7962. this.sidebarElement.subtitle = WebInspector.UIString("Loading\u2026");
  7963. this.sidebarElement.wait = true;
  7964. this._setupWorker();
  7965. this._numberOfChunks = 0;
  7966. this._savingToFile = false;
  7967.  
  7968. var delegate = new WebInspector.HeapSnapshotLoadFromFileDelegate(this);
  7969. var fileReader = this._createFileReader(file, delegate);
  7970. fileReader.start(this._receiver);
  7971. },
  7972.  
  7973. _createFileReader: function(file, delegate)
  7974. {
  7975. return new WebInspector.ChunkedFileReader(file, 10000000, delegate);
  7976. },
  7977.  
  7978. __proto__: WebInspector.ProfileHeader.prototype
  7979. }
  7980.  
  7981.  
  7982. WebInspector.HeapSnapshotLoadFromFileDelegate = function(snapshotHeader)
  7983. {
  7984. this._snapshotHeader = snapshotHeader;
  7985. }
  7986.  
  7987. WebInspector.HeapSnapshotLoadFromFileDelegate.prototype = {
  7988. onTransferStarted: function()
  7989. {
  7990. },
  7991.  
  7992.  
  7993. onChunkTransferred: function(reader)
  7994. {
  7995. this._snapshotHeader._updateTransferProgress(reader.loadedSize(), reader.fileSize());
  7996. },
  7997.  
  7998. onTransferFinished: function()
  7999. {
  8000. this._snapshotHeader.finishHeapSnapshot();
  8001. },
  8002.  
  8003.  
  8004. onError: function (reader, e)
  8005. {
  8006. switch(e.target.error.code) {
  8007. case e.target.error.NOT_FOUND_ERR:
  8008. this._snapshotHeader.sidebarElement.subtitle = WebInspector.UIString("'%s' not found.", reader.fileName());
  8009. break;
  8010. case e.target.error.NOT_READABLE_ERR:
  8011. this._snapshotHeader.sidebarElement.subtitle = WebInspector.UIString("'%s' is not readable", reader.fileName());
  8012. break;
  8013. case e.target.error.ABORT_ERR:
  8014. break;
  8015. default:
  8016. this._snapshotHeader.sidebarElement.subtitle = WebInspector.UIString("'%s' error %d", reader.fileName(), e.target.error.code);
  8017. }
  8018. }
  8019. }
  8020. ;
  8021.  
  8022.  
  8023.  
  8024. WebInspector.HeapSnapshotWorkerDispatcher = function(globalObject, postMessage)
  8025. {
  8026. this._objects = [];
  8027. this._global = globalObject;
  8028. this._postMessage = postMessage;
  8029. }
  8030.  
  8031. WebInspector.HeapSnapshotWorkerDispatcher.prototype = {
  8032. _findFunction: function(name)
  8033. {
  8034. var path = name.split(".");
  8035. var result = this._global;
  8036. for (var i = 0; i < path.length; ++i)
  8037. result = result[path[i]];
  8038. return result;
  8039. },
  8040.  
  8041. dispatchMessage: function(event)
  8042. {
  8043. var data = event.data;
  8044. var response = {callId: data.callId};
  8045. try {
  8046. switch (data.disposition) {
  8047. case "create": {
  8048. var constructorFunction = this._findFunction(data.methodName);
  8049. this._objects[data.objectId] = new constructorFunction();
  8050. break;
  8051. }
  8052. case "dispose": {
  8053. delete this._objects[data.objectId];
  8054. break;
  8055. }
  8056. case "getter": {
  8057. var object = this._objects[data.objectId];
  8058. var result = object[data.methodName];
  8059. response.result = result;
  8060. break;
  8061. }
  8062. case "factory": {
  8063. var object = this._objects[data.objectId];
  8064. var result = object[data.methodName].apply(object, data.methodArguments);
  8065. if (result)
  8066. this._objects[data.newObjectId] = result;
  8067. response.result = !!result;
  8068. break;
  8069. }
  8070. case "method": {
  8071. var object = this._objects[data.objectId];
  8072. response.result = object[data.methodName].apply(object, data.methodArguments);
  8073. break;
  8074. }
  8075. }
  8076. } catch (e) {
  8077. response.error = e.toString();
  8078. response.errorCallStack = e.stack;
  8079. if (data.methodName)
  8080. response.errorMethodName = data.methodName;
  8081. }
  8082. this._postMessage(response);
  8083. }
  8084. };
  8085. ;
  8086.  
  8087.  
  8088.  
  8089. WebInspector.NativeMemorySnapshotView = function(profile)
  8090. {
  8091. WebInspector.View.call(this);
  8092. this.registerRequiredCSS("nativeMemoryProfiler.css");
  8093.  
  8094. this.element.addStyleClass("native-snapshot-view");
  8095. this._containmentDataGrid = new WebInspector.NativeSnapshotDataGrid(profile._memoryBlock);
  8096. this._containmentDataGrid.show(this.element);
  8097.  
  8098. this._heapGraphDataGrid = new WebInspector.NativeHeapGraphDataGrid(new WebInspector.NativeHeapGraph(profile._graph));
  8099.  
  8100. this._viewSelectElement = document.createElement("select");
  8101. this._viewSelectElement.className = "status-bar-item";
  8102. this._viewSelectElement.addEventListener("change", this._onSelectedViewChanged.bind(this), false);
  8103.  
  8104. this._views = [{title: "Aggregated", view: this._containmentDataGrid},
  8105. {title: "Graph", view: this._heapGraphDataGrid}];
  8106. this._currentViewIndex = 0;
  8107. for (var i = 0; i < this._views.length; ++i) {
  8108. var view = this._views[i];
  8109. var option = document.createElement("option");
  8110. option.label = WebInspector.UIString(view.title);
  8111. this._viewSelectElement.appendChild(option);
  8112. }
  8113. }
  8114.  
  8115. WebInspector.NativeMemorySnapshotView.prototype = {
  8116. _onSelectedViewChanged: function(event)
  8117. {
  8118. var index = event.target.selectedIndex;
  8119. if (index === this._currentViewIndex)
  8120. return;
  8121.  
  8122. var currentView = this._views[this._currentViewIndex].view;
  8123. currentView.detach();
  8124.  
  8125. this._currentViewIndex = index;
  8126. var selectedView = this._views[index].view;
  8127. selectedView.show(this.element);
  8128. },
  8129.  
  8130. get statusBarItems()
  8131. {
  8132. var span = document.createElement("span");
  8133. span.className = "status-bar-select-container";
  8134. span.appendChild(this._viewSelectElement);
  8135. return [span];
  8136. },
  8137.  
  8138. __proto__: WebInspector.View.prototype
  8139. }
  8140.  
  8141.  
  8142.  
  8143.  
  8144. WebInspector.NativeSnapshotDataGrid = function(profile)
  8145. {
  8146. var columns = {
  8147. name: { title: WebInspector.UIString("Object"), width: "200px", disclosure: true, sortable: true },
  8148. size: { title: WebInspector.UIString("Size"), sortable: true, sort: "descending" },
  8149. };
  8150. WebInspector.DataGrid.call(this, columns);
  8151. this._totalNode = new WebInspector.NativeSnapshotNode(profile, profile);
  8152. if (WebInspector.settings.showNativeSnapshotUninstrumentedSize.get()) {
  8153. this.setRootNode(new WebInspector.DataGridNode(null, true));
  8154. this.rootNode().appendChild(this._totalNode)
  8155. this._totalNode.expand();
  8156. } else {
  8157. this.setRootNode(this._totalNode);
  8158. this._totalNode._populate();
  8159. }
  8160. this.addEventListener("sorting changed", this.sortingChanged.bind(this), this);
  8161. }
  8162.  
  8163. WebInspector.NativeSnapshotDataGrid.prototype = {
  8164. sortingChanged: function()
  8165. {
  8166. var expandedNodes = {};
  8167. this._totalNode._storeState(expandedNodes);
  8168. this._totalNode.removeChildren();
  8169. this._totalNode._populate();
  8170. this._totalNode._shouldRefreshChildren = true;
  8171. this._totalNode._restoreState(expandedNodes);
  8172. },
  8173.  
  8174.  
  8175. _sortingFunction: function(nodeA, nodeB)
  8176. {
  8177. var sortColumnIdentifier = this.sortColumnIdentifier;
  8178. var sortAscending = this.sortOrder === "ascending";
  8179. var field1 = nodeA[sortColumnIdentifier];
  8180. var field2 = nodeB[sortColumnIdentifier];
  8181. var result = field1 < field2 ? -1 : (field1 > field2 ? 1 : 0);
  8182. if (!sortAscending)
  8183. result = -result;
  8184. return result;
  8185. },
  8186.  
  8187. __proto__: WebInspector.DataGrid.prototype
  8188. }
  8189.  
  8190.  
  8191. WebInspector.NativeSnapshotNode = function(nodeData, profile)
  8192. {
  8193. this._nodeData = nodeData;
  8194. this._profile = profile;
  8195. var viewProperties = WebInspector.MemoryBlockViewProperties._forMemoryBlock(nodeData);
  8196. var data = { name: viewProperties._description, size: this._nodeData.size };
  8197. var hasChildren = !!nodeData.children && nodeData.children.length !== 0;
  8198. WebInspector.DataGridNode.call(this, data, hasChildren);
  8199. this.addEventListener("populate", this._populate, this);
  8200. }
  8201.  
  8202. WebInspector.NativeSnapshotNode.prototype = {
  8203.  
  8204. createCell: function(columnIdentifier)
  8205. {
  8206. var cell = columnIdentifier === "size" ?
  8207. this._createSizeCell(columnIdentifier) :
  8208. WebInspector.DataGridNode.prototype.createCell.call(this, columnIdentifier);
  8209. return cell;
  8210. },
  8211.  
  8212.  
  8213. _storeState: function(expandedNodes)
  8214. {
  8215. if (!this.expanded)
  8216. return;
  8217. expandedNodes[this.uid()] = true;
  8218. for (var i in this.children)
  8219. this.children[i]._storeState(expandedNodes);
  8220. },
  8221.  
  8222.  
  8223. _restoreState: function(expandedNodes)
  8224. {
  8225. if (!expandedNodes[this.uid()])
  8226. return;
  8227. this.expand();
  8228. for (var i in this.children)
  8229. this.children[i]._restoreState(expandedNodes);
  8230. },
  8231.  
  8232.  
  8233. uid: function()
  8234. {
  8235. if (!this._uid)
  8236. this._uid = (!this.parent || !this.parent.uid ? "" : this.parent.uid() || "") + "/" + this._nodeData.name;
  8237. return this._uid;
  8238. },
  8239.  
  8240.  
  8241. _createSizeCell: function(columnIdentifier)
  8242. {
  8243. var node = this;
  8244. var viewProperties = null;
  8245. var dimmed = false;
  8246. while (!viewProperties || viewProperties._fillStyle === "inherit") {
  8247. viewProperties = WebInspector.MemoryBlockViewProperties._forMemoryBlock(node._nodeData);
  8248. if (viewProperties._fillStyle === "inherit")
  8249. dimmed = true;
  8250. node = node.parent;
  8251. }
  8252.  
  8253. var sizeKB = this._nodeData.size / 1024;
  8254. var totalSize = this._profile.size;
  8255. var percentage = this._nodeData.size / totalSize  * 100;
  8256.  
  8257. var cell = document.createElement("td");
  8258. cell.className = columnIdentifier + "-column";
  8259.  
  8260. var textDiv = document.createElement("div");
  8261. textDiv.textContent = Number.withThousandsSeparator(sizeKB.toFixed(0)) + "\u2009" + WebInspector.UIString("KB");
  8262. textDiv.className = "size-text";
  8263. cell.appendChild(textDiv);
  8264.  
  8265. var barDiv = document.createElement("div");
  8266. barDiv.className = "size-bar";
  8267. barDiv.style.width = percentage + "%";
  8268. barDiv.style.backgroundColor = viewProperties._fillStyle;
  8269.  
  8270. var fillerDiv = document.createElement("div");
  8271. fillerDiv.className = "percent-text"
  8272. barDiv.appendChild(fillerDiv);
  8273. var percentDiv = document.createElement("div");
  8274. percentDiv.textContent = percentage.toFixed(1) + "%";
  8275. percentDiv.className = "percent-text"
  8276. barDiv.appendChild(percentDiv);
  8277.  
  8278. var barHolderDiv = document.createElement("div");
  8279. if (dimmed)
  8280. barHolderDiv.className = "dimmed";
  8281. barHolderDiv.appendChild(barDiv);
  8282. cell.appendChild(barHolderDiv);
  8283.  
  8284. return cell;
  8285. },
  8286.  
  8287. _populate: function() {
  8288. this.removeEventListener("populate", this._populate, this);
  8289. this._nodeData.children.sort(this.dataGrid._sortingFunction.bind(this.dataGrid));
  8290. for (var node in this._nodeData.children) {
  8291. var nodeData = this._nodeData.children[node];
  8292. if (WebInspector.settings.showNativeSnapshotUninstrumentedSize.get() || nodeData.name !== "Other")
  8293. this.appendChild(new WebInspector.NativeSnapshotNode(nodeData, this._profile));
  8294. }
  8295. },
  8296.  
  8297. __proto__: WebInspector.DataGridNode.prototype
  8298. }
  8299.  
  8300.  
  8301.  
  8302. WebInspector.NativeHeapGraphNode = function(graph, position)
  8303. {
  8304. this._graph = graph;
  8305. this._position = position;
  8306. }
  8307.  
  8308. WebInspector.NativeHeapGraphNode.prototype = {
  8309. id: function()
  8310. {
  8311. return this._position / this._graph._nodeFieldCount;
  8312. },
  8313.  
  8314. type: function()
  8315. {
  8316. return this._getStringField(this._graph._nodeTypeOffset);
  8317. },
  8318.  
  8319. size: function()
  8320. {
  8321. return this._graph._rawGraph.nodes[this._position + this._graph._nodeSizeOffset];
  8322. },
  8323.  
  8324. className: function()
  8325. {
  8326. return this._getStringField(this._graph._nodeClassNameOffset);
  8327. },
  8328.  
  8329. name: function()
  8330. {
  8331. return this._getStringField(this._graph._nodeNameOffset);
  8332. },
  8333.  
  8334. hasReferencedNodes: function()
  8335. {
  8336. return this._afterLastEdgePosition() > this._firstEdgePoistion();
  8337. },
  8338.  
  8339. referencedNodes: function()
  8340. {
  8341. var edges = this._graph._rawGraph.edges;
  8342. var nodes = this._graph._rawGraph.nodes;
  8343. var edgeFieldCount = this._graph._edgeFieldCount;
  8344. var nodeFieldCount = this._graph._nodeFieldCount;
  8345.  
  8346. var firstEdgePosition = this._firstEdgePoistion();
  8347. var afterLastEdgePosition = this._afterLastEdgePosition();
  8348. var result = [];
  8349. for (var i = firstEdgePosition + this._graph._edgeTargetOffset; i < afterLastEdgePosition; i += edgeFieldCount)
  8350. result.push(new WebInspector.NativeHeapGraphNode(this._graph, edges[i] * nodeFieldCount));
  8351. return result;
  8352. },
  8353.  
  8354. _firstEdgePoistion: function()
  8355. {
  8356. return this._graph._rawGraph.nodes[this._position + this._graph._nodeFirstEdgeOffset] * this._graph._edgeFieldCount;
  8357. },
  8358.  
  8359. _afterLastEdgePosition: function()
  8360. {
  8361. var edges = this._graph._rawGraph.edges;
  8362. var nodes = this._graph._rawGraph.nodes;
  8363. var afterLastEdgePosition = nodes[this._position + this._graph._nodeFieldCount + this._graph._nodeFirstEdgeOffset];
  8364. if (afterLastEdgePosition)
  8365. afterLastEdgePosition *= this._graph._edgeFieldCount;
  8366. else
  8367. afterLastEdgePosition = edges.length;
  8368. return afterLastEdgePosition;
  8369. },
  8370.  
  8371. _getStringField: function(offset)
  8372. {
  8373. var typeIndex = this._graph._rawGraph.nodes[this._position + offset];
  8374. return this._graph._rawGraph.strings[typeIndex];
  8375. }
  8376. }
  8377.  
  8378.  
  8379.  
  8380. WebInspector.NativeHeapGraph = function(rawGraph)
  8381. {
  8382. this._rawGraph = rawGraph;
  8383.  
  8384. this._nodeFieldCount = 5;
  8385. this._nodeTypeOffset = 0;
  8386. this._nodeSizeOffset = 1;
  8387. this._nodeClassNameOffset = 2;
  8388. this._nodeNameOffset = 3;
  8389. this._nodeEdgeCountOffset = 4;
  8390. this._nodeFirstEdgeOffset = this._nodeEdgeCountOffset;
  8391.  
  8392. this._edgeFieldCount = 3;
  8393. this._edgeTypeOffset = 0;
  8394. this._edgeTargetOffset = 1;
  8395. this._edgeNameOffset = 2;
  8396.  
  8397. this._calculateNodeEdgeIndexes();
  8398. }
  8399.  
  8400. WebInspector.NativeHeapGraph.prototype = {
  8401. rootNodes: function()
  8402. {
  8403. var nodeHasIncomingEdges = new Uint8Array(this._rawGraph.nodes.length / this._nodeFieldCount);
  8404. var edges = this._rawGraph.edges;
  8405. var edgesLength = edges.length;
  8406. var edgeFieldCount = this._edgeFieldCount;
  8407. var nodeFieldCount = this._nodeFieldCount;
  8408. for (var i = this._edgeTargetOffset; i < edgesLength; i += edgeFieldCount) {
  8409. var targetIndex = edges[i];
  8410. nodeHasIncomingEdges[targetIndex] = 1;
  8411. }
  8412. var roots = [];
  8413. var nodeCount = nodeHasIncomingEdges.length;
  8414. for (var i = 0; i < nodeCount; i++) {
  8415. if (!nodeHasIncomingEdges[i])
  8416. roots.push(new WebInspector.NativeHeapGraphNode(this, i * nodeFieldCount));
  8417. }
  8418. return roots;
  8419. },
  8420.  
  8421. _calculateNodeEdgeIndexes: function()
  8422. {
  8423. var nodes = this._rawGraph.nodes;
  8424. var nodeFieldCount = this._nodeFieldCount;
  8425. var nodeLength = nodes.length;
  8426. var firstEdgeIndex = 0;
  8427. for (var i = this._nodeEdgeCountOffset; i < nodeLength; i += nodeFieldCount) {
  8428. var count = nodes[i];
  8429. nodes[i] = firstEdgeIndex;
  8430. firstEdgeIndex += count;
  8431. }
  8432. }
  8433. }
  8434.  
  8435.  
  8436.  
  8437. WebInspector.NativeHeapGraphDataGrid = function(nativeHeapGraph)
  8438. {
  8439. var columns = {
  8440. id: { title: WebInspector.UIString("id"), width: "80px", disclosure: true, sortable: true },
  8441. type: { title: WebInspector.UIString("Type"), width: "200px", sortable: true },
  8442. className: { title: WebInspector.UIString("Class name"), width: "200px", sortable: true },
  8443. name: { title: WebInspector.UIString("Name"), width: "200px", sortable: true },
  8444. size: { title: WebInspector.UIString("Size"), sortable: true, sort: "descending" },
  8445. };
  8446. WebInspector.DataGrid.call(this, columns);
  8447. this._nativeHeapGraph = nativeHeapGraph;
  8448. this._root = new WebInspector.NativeHeapGraphDataGridRoot(this._nativeHeapGraph);
  8449. this.setRootNode(this._root);
  8450. this._root._populate();
  8451. }
  8452.  
  8453. WebInspector.NativeHeapGraphDataGrid.prototype = {
  8454. __proto__: WebInspector.DataGrid.prototype
  8455. }
  8456.  
  8457.  
  8458.  
  8459. WebInspector.NativeHeapGraphDataGridRoot = function(graph)
  8460. {
  8461. WebInspector.DataGridNode.call(this, { id: "root" }, true);
  8462. this._graph = graph;
  8463. this.addEventListener("populate", this._populate, this);
  8464. }
  8465.  
  8466. WebInspector.NativeHeapGraphDataGridRoot.prototype = {
  8467. _populate: function() {
  8468. this.removeEventListener("populate", this._populate, this);
  8469. var roots = this._graph.rootNodes();
  8470. for (var i = 0; i < roots.length; i++)
  8471. this.appendChild(new WebInspector.NativeHeapGraphDataGridNode(roots[i]));
  8472. },
  8473.  
  8474. __proto__: WebInspector.DataGridNode.prototype
  8475. }
  8476.  
  8477.  
  8478.  
  8479. WebInspector.NativeHeapGraphDataGridNode = function(node)
  8480. {
  8481. var data = {
  8482. id: node.id(),
  8483. size: node.size(),
  8484. type: node.type(),
  8485. className: node.className(),
  8486. name: node.name(),
  8487. };
  8488. WebInspector.DataGridNode.call(this, data, node.hasReferencedNodes());
  8489. this._node = node;
  8490. this.addEventListener("populate", this._populate, this);
  8491. }
  8492.  
  8493. WebInspector.NativeHeapGraphDataGridNode.prototype = {
  8494. _populate: function() {
  8495. this.removeEventListener("populate", this._populate, this);
  8496. var children = this._node.referencedNodes();
  8497. for (var i = 0; i < children.length; i++)
  8498. this.appendChild(new WebInspector.NativeHeapGraphDataGridNode(children[i]));
  8499. },
  8500.  
  8501. __proto__: WebInspector.DataGridNode.prototype
  8502. }
  8503.  
  8504.  
  8505.  
  8506. WebInspector.NativeMemoryProfileType = function()
  8507. {
  8508. WebInspector.ProfileType.call(this, WebInspector.NativeMemoryProfileType.TypeId, WebInspector.UIString("Take Native Memory Snapshot"));
  8509. this._nextProfileUid = 1;
  8510. }
  8511.  
  8512. WebInspector.NativeMemoryProfileType.TypeId = "NATIVE_MEMORY";
  8513.  
  8514. WebInspector.NativeMemoryProfileType.prototype = {
  8515. get buttonTooltip()
  8516. {
  8517. return WebInspector.UIString("Take native memory snapshot.");
  8518. },
  8519.  
  8520.  
  8521. buttonClicked: function(profilesPanel)
  8522. {
  8523. var profileHeader = new WebInspector.NativeMemoryProfileHeader(this, WebInspector.UIString("Snapshot %d", this._nextProfileUid), this._nextProfileUid);
  8524. ++this._nextProfileUid;
  8525. profileHeader.isTemporary = true;
  8526. profilesPanel.addProfileHeader(profileHeader);
  8527.  
  8528. function didReceiveMemorySnapshot(error, memoryBlock, graph)
  8529. {
  8530. if (memoryBlock.size && memoryBlock.children) {
  8531. var knownSize = 0;
  8532. for (var i = 0; i < memoryBlock.children.length; i++) {
  8533. var size = memoryBlock.children[i].size;
  8534. if (size)
  8535. knownSize += size;
  8536. }
  8537. var otherSize = memoryBlock.size - knownSize;
  8538.  
  8539. if (otherSize) {
  8540. memoryBlock.children.push({
  8541. name: "Other",
  8542. size: otherSize
  8543. });
  8544. }
  8545. }
  8546. profileHeader._memoryBlock = memoryBlock;
  8547. profileHeader._graph = graph;
  8548. profileHeader.isTemporary = false;
  8549. profileHeader.sidebarElement.subtitle = Number.bytesToString( (memoryBlock.size));
  8550. }
  8551. MemoryAgent.getProcessMemoryDistribution(true, didReceiveMemorySnapshot.bind(this));
  8552. return false;
  8553. },
  8554.  
  8555. get treeItemTitle()
  8556. {
  8557. return WebInspector.UIString("MEMORY DISTRIBUTION");
  8558. },
  8559.  
  8560. get description()
  8561. {
  8562. return WebInspector.UIString("Native memory snapshot profiles show memory distribution among browser subsystems");
  8563. },
  8564.  
  8565.  
  8566. createTemporaryProfile: function(title)
  8567. {
  8568. title = title || WebInspector.UIString("Snapshotting\u2026");
  8569. return new WebInspector.NativeMemoryProfileHeader(this, title);
  8570. },
  8571.  
  8572.  
  8573. createProfile: function(profile)
  8574. {
  8575. return new WebInspector.NativeMemoryProfileHeader(this, profile.title, -1);
  8576. },
  8577.  
  8578. __proto__: WebInspector.ProfileType.prototype
  8579. }
  8580.  
  8581.  
  8582. WebInspector.NativeMemoryProfileHeader = function(type, title, uid)
  8583. {
  8584. WebInspector.ProfileHeader.call(this, type, title, uid);
  8585.  
  8586.  
  8587. this._memoryBlock = null;
  8588. }
  8589.  
  8590. WebInspector.NativeMemoryProfileHeader.prototype = {
  8591.  
  8592. createSidebarTreeElement: function()
  8593. {
  8594. return new WebInspector.ProfileSidebarTreeElement(this, WebInspector.UIString("Snapshot %d"), "heap-snapshot-sidebar-tree-item");
  8595. },
  8596.  
  8597.  
  8598. createView: function(profilesPanel)
  8599. {
  8600. return new WebInspector.NativeMemorySnapshotView(this);
  8601. },
  8602.  
  8603. __proto__: WebInspector.ProfileHeader.prototype
  8604. }
  8605.  
  8606.  
  8607. WebInspector.MemoryBlockViewProperties = function(fillStyle, name, description)
  8608. {
  8609. this._fillStyle = fillStyle;
  8610. this._name = name;
  8611. this._description = description;
  8612. }
  8613.  
  8614.  
  8615. WebInspector.MemoryBlockViewProperties._standardBlocks = null;
  8616.  
  8617. WebInspector.MemoryBlockViewProperties._initialize = function()
  8618. {
  8619. if (WebInspector.MemoryBlockViewProperties._standardBlocks)
  8620. return;
  8621. WebInspector.MemoryBlockViewProperties._standardBlocks = {};
  8622. function addBlock(fillStyle, name, description)
  8623. {
  8624. WebInspector.MemoryBlockViewProperties._standardBlocks[name] = new WebInspector.MemoryBlockViewProperties(fillStyle, name, WebInspector.UIString(description));
  8625. }
  8626. addBlock("hsl(  0,  0%,  60%)", "ProcessPrivateMemory", "Total");
  8627. addBlock("hsl(  0,  0%,  80%)", "OwnersTypePlaceholder", "OwnersTypePlaceholder");
  8628. addBlock("hsl(  0,  0%,  60%)", "Other", "Other");
  8629. addBlock("hsl(220, 80%,  70%)", "Page", "Page structures");
  8630. addBlock("hsl(100, 60%,  50%)", "JSHeap", "JavaScript heap");
  8631. addBlock("hsl( 90, 40%,  80%)", "JSExternalResources", "JavaScript external resources");
  8632. addBlock("hsl( 90, 60%,  80%)", "JSExternalArrays", "JavaScript external arrays");
  8633. addBlock("hsl( 90, 60%,  80%)", "JSExternalStrings", "JavaScript external strings");
  8634. addBlock("hsl(  0, 80%,  60%)", "WebInspector", "Inspector data");
  8635. addBlock("hsl( 36, 90%,  50%)", "MemoryCache", "Memory cache resources");
  8636. addBlock("hsl( 40, 80%,  80%)", "GlyphCache", "Glyph cache resources");
  8637. addBlock("hsl( 35, 80%,  80%)", "DOMStorageCache", "DOM storage cache");
  8638. addBlock("hsl( 60, 80%,  60%)", "RenderTree", "Render tree");
  8639. addBlock("hsl( 20, 80%,  50%)", "MallocWaste", "Memory allocator waste");
  8640. }
  8641.  
  8642. WebInspector.MemoryBlockViewProperties._forMemoryBlock = function(memoryBlock)
  8643. {
  8644. WebInspector.MemoryBlockViewProperties._initialize();
  8645. var result = WebInspector.MemoryBlockViewProperties._standardBlocks[memoryBlock.name];
  8646. if (result)
  8647. return result;
  8648. return new WebInspector.MemoryBlockViewProperties("inherit", memoryBlock.name, memoryBlock.name);
  8649. }
  8650.  
  8651.  
  8652.  
  8653. WebInspector.NativeMemoryPieChart = function(memorySnapshot)
  8654. {
  8655. WebInspector.View.call(this);
  8656. this._memorySnapshot = memorySnapshot;
  8657. this.element = document.createElement("div");
  8658. this.element.addStyleClass("memory-pie-chart-container");
  8659. this._memoryBlockList = this.element.createChild("div", "memory-blocks-list");
  8660.  
  8661. this._canvasContainer = this.element.createChild("div", "memory-pie-chart");
  8662. this._canvas = this._canvasContainer.createChild("canvas");
  8663. this._addBlockLabels(memorySnapshot, true);
  8664. }
  8665.  
  8666. WebInspector.NativeMemoryPieChart.prototype = {
  8667.  
  8668. onResize: function()
  8669. {
  8670. this._updateSize();
  8671. this._paint();
  8672. },
  8673.  
  8674. _updateSize: function()
  8675. {
  8676. var width = this._canvasContainer.clientWidth - 5;
  8677. var height = this._canvasContainer.clientHeight - 5;
  8678. this._canvas.width = width;
  8679. this._canvas.height = height;
  8680. },
  8681.  
  8682. _addBlockLabels: function(memoryBlock, includeChildren)
  8683. {
  8684. var viewProperties = WebInspector.MemoryBlockViewProperties._forMemoryBlock(memoryBlock);
  8685. var title = viewProperties._description + ": " + Number.bytesToString(memoryBlock.size);
  8686.  
  8687. var swatchElement = this._memoryBlockList.createChild("div", "item");
  8688. swatchElement.createChild("div", "swatch").style.backgroundColor = viewProperties._fillStyle;
  8689. swatchElement.createChild("span", "title").textContent = title;
  8690.  
  8691. if (!memoryBlock.children || !includeChildren)
  8692. return;
  8693. for (var i = 0; i < memoryBlock.children.length; i++)
  8694. this._addBlockLabels(memoryBlock.children[i], false);
  8695. },
  8696.  
  8697. _paint: function()
  8698. {
  8699. this._clear();
  8700. var width = this._canvas.width;
  8701. var height = this._canvas.height;
  8702.  
  8703. var x = width / 2;
  8704. var y = height / 2;
  8705. var radius = 200;
  8706.  
  8707. var ctx = this._canvas.getContext("2d");
  8708. ctx.beginPath();
  8709. ctx.arc(x, y, radius, 0, Math.PI*2, false);
  8710. ctx.lineWidth = 1;
  8711. ctx.strokeStyle = "rgba(130, 130, 130, 0.8)";
  8712. ctx.stroke();
  8713. ctx.closePath();
  8714.  
  8715. var currentAngle = 0;
  8716. var memoryBlock = this._memorySnapshot;
  8717.  
  8718. function paintPercentAndLabel(fraction, title, midAngle)
  8719. {
  8720. ctx.beginPath();
  8721. ctx.font = "13px Arial";
  8722. ctx.fillStyle = "rgba(10, 10, 10, 0.8)";
  8723.  
  8724. var textX = x + (radius + 10) * Math.cos(midAngle);
  8725. var textY = y + (radius + 10) * Math.sin(midAngle);
  8726. var relativeOffset = -Math.cos(midAngle) / Math.sin(Math.PI / 12);
  8727. relativeOffset = Number.constrain(relativeOffset, -1, 1);
  8728. var metrics = ctx.measureText(title);
  8729. textX -= metrics.width * (relativeOffset + 1) / 2;
  8730. textY += 5;
  8731. ctx.fillText(title, textX, textY);
  8732.  
  8733.  
  8734. if (fraction > 0.03) {
  8735. textX = x + radius * Math.cos(midAngle) / 2;
  8736. textY = y + radius * Math.sin(midAngle) / 2;
  8737. ctx.fillText((100 * fraction).toFixed(0) + "%", textX - 8, textY + 5);
  8738. }
  8739.  
  8740. ctx.closePath();
  8741. }
  8742.  
  8743. if (!memoryBlock.children)
  8744. return;
  8745. var total = memoryBlock.size;
  8746. for (var i = 0; i < memoryBlock.children.length; i++) {
  8747. var child = memoryBlock.children[i];
  8748. if (!child.size)
  8749. continue;
  8750. var viewProperties = WebInspector.MemoryBlockViewProperties._forMemoryBlock(child);
  8751. var angleSpan = Math.PI * 2 * (child.size / total);
  8752. ctx.beginPath();
  8753. ctx.moveTo(x, y);
  8754. ctx.lineTo(x + radius * Math.cos(currentAngle), y + radius * Math.sin(currentAngle));
  8755. ctx.arc(x, y, radius, currentAngle, currentAngle + angleSpan, false);
  8756. ctx.lineWidth = 0.5;
  8757. ctx.lineTo(x, y);
  8758. ctx.fillStyle = viewProperties._fillStyle;
  8759. ctx.strokeStyle = "rgba(100, 100, 100, 0.8)";
  8760. ctx.fill();
  8761. ctx.stroke();
  8762. ctx.closePath();
  8763.  
  8764. paintPercentAndLabel(child.size / total, viewProperties._description, currentAngle + angleSpan / 2);
  8765.  
  8766. currentAngle += angleSpan;
  8767. }
  8768. },
  8769.  
  8770. _clear: function() {
  8771. var ctx = this._canvas.getContext("2d");
  8772. ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  8773. },
  8774.  
  8775. __proto__: WebInspector.View.prototype
  8776. }
  8777.  
  8778.  
  8779. WebInspector.NativeMemoryBarChart = function()
  8780. {
  8781. WebInspector.View.call(this);
  8782. this.registerRequiredCSS("nativeMemoryProfiler.css");
  8783. this._memorySnapshot = null;
  8784. this.element = document.createElement("div");
  8785. this._table = this.element.createChild("table");
  8786. this._divs = {};
  8787. var row = this._table.insertRow();
  8788. this._totalDiv = row.insertCell().createChild("div");
  8789. this._totalDiv.addStyleClass("memory-bar-chart-total");
  8790. row.insertCell();
  8791. }
  8792.  
  8793. WebInspector.NativeMemoryBarChart.prototype = {
  8794. _updateStats: function()
  8795. {
  8796.  
  8797.  
  8798. function didReceiveMemorySnapshot(error, memoryBlock, graph)
  8799. {
  8800. if (memoryBlock.size && memoryBlock.children) {
  8801. var knownSize = 0;
  8802. for (var i = 0; i < memoryBlock.children.length; i++) {
  8803. var size = memoryBlock.children[i].size;
  8804. if (size)
  8805. knownSize += size;
  8806. }
  8807. var otherSize = memoryBlock.size - knownSize;
  8808.  
  8809. if (otherSize) {
  8810. memoryBlock.children.push({
  8811. name: "Other",
  8812. size: otherSize
  8813. });
  8814. }
  8815. }
  8816. this._memorySnapshot = memoryBlock;
  8817. this._updateView();
  8818. }
  8819. MemoryAgent.getProcessMemoryDistribution(false, didReceiveMemorySnapshot.bind(this));
  8820. },
  8821.  
  8822.  
  8823. willHide: function()
  8824. {
  8825. clearInterval(this._timerId);
  8826. },
  8827.  
  8828.  
  8829. wasShown: function()
  8830. {
  8831. this._timerId = setInterval(this._updateStats.bind(this), 1000);
  8832. },
  8833.  
  8834. _updateView: function()
  8835. {
  8836. var memoryBlock = this._memorySnapshot;
  8837. if (!memoryBlock)
  8838. return;
  8839.  
  8840. var MB = 1024 * 1024;
  8841. var maxSize = 100 * MB;
  8842. for (var i = 0; i < memoryBlock.children.length; ++i)
  8843. maxSize = Math.max(maxSize, memoryBlock.children[i].size);
  8844. var maxBarLength = 500;
  8845. var barLengthSizeRatio = maxBarLength / maxSize;
  8846.  
  8847. for (var i = memoryBlock.children.length - 1; i >= 0 ; --i) {
  8848. var child = memoryBlock.children[i];
  8849. var name = child.name;
  8850. var divs = this._divs[name];
  8851. if (!divs) {
  8852. var row = this._table.insertRow();
  8853. var nameDiv = row.insertCell(-1).createChild("div");
  8854. var viewProperties = WebInspector.MemoryBlockViewProperties._forMemoryBlock(child);
  8855. var title = viewProperties._description;
  8856. nameDiv.textContent = title;
  8857. nameDiv.addStyleClass("memory-bar-chart-name");
  8858. var barCell = row.insertCell(-1);
  8859. var barDiv = barCell.createChild("div");
  8860. barDiv.addStyleClass("memory-bar-chart-bar");
  8861. viewProperties = WebInspector.MemoryBlockViewProperties._forMemoryBlock(child);
  8862. barDiv.style.backgroundColor = viewProperties._fillStyle;
  8863. var unusedDiv = barDiv.createChild("div");
  8864. unusedDiv.addStyleClass("memory-bar-chart-unused");
  8865. var percentDiv = barDiv.createChild("div");
  8866. percentDiv.addStyleClass("memory-bar-chart-percent");
  8867. var sizeDiv = barCell.createChild("div");
  8868. sizeDiv.addStyleClass("memory-bar-chart-size");
  8869. divs = this._divs[name] = { barDiv: barDiv, unusedDiv: unusedDiv, percentDiv: percentDiv, sizeDiv: sizeDiv };
  8870. }
  8871. var unusedSize = 0;
  8872. if (!!child.children) {
  8873. var unusedName = name + ".Unused";
  8874. for (var j = 0; j < child.children.length; ++j) {
  8875. if (child.children[j].name === unusedName) {
  8876. unusedSize = child.children[j].size;
  8877. break;
  8878. }
  8879. }
  8880. }
  8881. var unusedLength = unusedSize * barLengthSizeRatio;
  8882. var barLength = child.size * barLengthSizeRatio;
  8883.  
  8884. divs.barDiv.style.width = barLength + "px";
  8885. divs.unusedDiv.style.width = unusedLength + "px";
  8886. divs.percentDiv.textContent = barLength > 20 ? (child.size / memoryBlock.size * 100).toFixed(0) + "%" : "";
  8887. divs.sizeDiv.textContent = (child.size / MB).toFixed(1) + "\u2009MB";
  8888. }
  8889.  
  8890. var memoryBlockViewProperties = WebInspector.MemoryBlockViewProperties._forMemoryBlock(memoryBlock);
  8891. this._totalDiv.textContent = memoryBlockViewProperties._description + ": " + (memoryBlock.size / MB).toFixed(1) + "\u2009MB";
  8892. },
  8893.  
  8894. __proto__: WebInspector.View.prototype
  8895. }
  8896. ;
  8897.  
  8898.  
  8899.  
  8900. WebInspector.ProfileLauncherView = function(profilesPanel)
  8901. {
  8902. WebInspector.View.call(this);
  8903.  
  8904. this._panel = profilesPanel;
  8905. this._profileRunning = false;
  8906.  
  8907. this.element.addStyleClass("profile-launcher-view");
  8908. this.element.addStyleClass("panel-enabler-view");
  8909.  
  8910. this._contentElement = document.createElement("div");
  8911. this._contentElement.className = "profile-launcher-view-content";
  8912. this.element.appendChild(this._contentElement);
  8913.  
  8914. var header = this._contentElement.createChild("h1");
  8915. header.textContent = WebInspector.UIString("Select profiling type");
  8916.  
  8917. this._profileTypeSelectorForm = this._contentElement.createChild("form");
  8918.  
  8919. if (WebInspector.experimentsSettings.liveNativeMemoryChart.isEnabled()) {
  8920. this._nativeMemoryElement = document.createElement("div");
  8921. this._contentElement.appendChild(this._nativeMemoryElement);
  8922. this._nativeMemoryLiveChart = new WebInspector.NativeMemoryBarChart();
  8923. this._nativeMemoryLiveChart.show(this._nativeMemoryElement);
  8924. }
  8925.  
  8926. this._contentElement.createChild("div", "flexible-space");
  8927.  
  8928. this._controlButton = this._contentElement.createChild("button", "control-profiling");
  8929. this._controlButton.addEventListener("click", this._controlButtonClicked.bind(this), false);
  8930. this._updateControls();
  8931. }
  8932.  
  8933. WebInspector.ProfileLauncherView.EventTypes = {
  8934. ProfileTypeSelected: "profile-type-selected"
  8935. }
  8936.  
  8937. WebInspector.ProfileLauncherView.prototype = {
  8938.  
  8939. addProfileType: function(profileType)
  8940. {
  8941. var checked = !this._profileTypeSelectorForm.children.length;
  8942. var labelElement = this._profileTypeSelectorForm.createChild("label");
  8943. labelElement.textContent = profileType.name;
  8944. var optionElement = document.createElement("input");
  8945. labelElement.insertBefore(optionElement, labelElement.firstChild);
  8946. optionElement.type = "radio";
  8947. optionElement.name = "profile-type";
  8948. if (checked) {
  8949. optionElement.checked = checked;
  8950. this.dispatchEventToListeners(WebInspector.ProfileLauncherView.EventTypes.ProfileTypeSelected, profileType);
  8951. }
  8952. optionElement.addEventListener("change", this._profileTypeChanged.bind(this, profileType), false);
  8953. var descriptionElement = labelElement.createChild("p");
  8954. descriptionElement.textContent = profileType.description;
  8955. },
  8956.  
  8957. _controlButtonClicked: function()
  8958. {
  8959. this._panel.toggleRecordButton();
  8960. },
  8961.  
  8962. _updateControls: function()
  8963. {
  8964. if (this._isProfiling) {
  8965. this._profileTypeSelectorForm.disabled = true;
  8966. this._controlButton.addStyleClass("running");
  8967. this._controlButton.textContent = WebInspector.UIString("Stop");
  8968. } else {
  8969. this._profileTypeSelectorForm.disabled = false;
  8970. this._controlButton.removeStyleClass("running");
  8971. this._controlButton.textContent = WebInspector.UIString("Start");
  8972. }
  8973. },
  8974.  
  8975.  
  8976. _profileTypeChanged: function(profileType, event)
  8977. {
  8978. this.dispatchEventToListeners(WebInspector.ProfileLauncherView.EventTypes.ProfileTypeSelected, profileType);
  8979. },
  8980.  
  8981. profileStarted: function()
  8982. {
  8983. this._isProfiling = true;
  8984. this._updateControls();
  8985. },
  8986.  
  8987. profileFinished: function()
  8988. {
  8989. this._isProfiling = false;
  8990. this._updateControls();
  8991. },
  8992.  
  8993. __proto__: WebInspector.View.prototype
  8994. }
  8995. ;
  8996.  
  8997.  
  8998.  
  8999. WebInspector.TopDownProfileDataGridNode = function(  profileView,   profileNode,   owningTree)
  9000. {
  9001. var hasChildren = (profileNode.children && profileNode.children.length);
  9002.  
  9003. WebInspector.ProfileDataGridNode.call(this, profileView, profileNode, owningTree, hasChildren);
  9004.  
  9005. this._remainingChildren = profileNode.children;
  9006. }
  9007.  
  9008. WebInspector.TopDownProfileDataGridNode.prototype = {
  9009. _sharedPopulate: function()
  9010. {
  9011. var children = this._remainingChildren;
  9012. var childrenLength = children.length;
  9013.  
  9014. for (var i = 0; i < childrenLength; ++i)
  9015. this.appendChild(new WebInspector.TopDownProfileDataGridNode(this.profileView, children[i], this.tree));
  9016.  
  9017. this._remainingChildren = null;
  9018. },
  9019.  
  9020. _exclude: function(aCallUID)
  9021. {
  9022. if (this._remainingChildren)
  9023. this._populate();
  9024.  
  9025. this._save();
  9026.  
  9027. var children = this.children;
  9028. var index = this.children.length;
  9029.  
  9030. while (index--)
  9031. children[index]._exclude(aCallUID);
  9032.  
  9033. var child = this.childrenByCallUID[aCallUID];
  9034.  
  9035. if (child)
  9036. this._merge(child, true);
  9037. },
  9038.  
  9039. __proto__: WebInspector.ProfileDataGridNode.prototype
  9040. }
  9041.  
  9042.  
  9043. WebInspector.TopDownProfileDataGridTree = function(  profileView,   profileNode)
  9044. {
  9045. WebInspector.ProfileDataGridTree.call(this, profileView, profileNode);
  9046.  
  9047. this._remainingChildren = profileNode.children;
  9048.  
  9049. var any =  this;
  9050. var node =  any;
  9051. WebInspector.TopDownProfileDataGridNode.prototype._populate.call(node);
  9052. }
  9053.  
  9054. WebInspector.TopDownProfileDataGridTree.prototype = {
  9055. focus: function(  profileDataGrideNode)
  9056. {
  9057. if (!profileDataGrideNode)
  9058. return;
  9059.  
  9060. this._save();
  9061. profileDataGrideNode.savePosition();
  9062.  
  9063. this.children = [profileDataGrideNode];
  9064. this.totalTime = profileDataGrideNode.totalTime;
  9065. },
  9066.  
  9067. exclude: function(  profileDataGrideNode)
  9068. {
  9069. if (!profileDataGrideNode)
  9070. return;
  9071.  
  9072. this._save();
  9073.  
  9074. var excludedCallUID = profileDataGrideNode.callUID;
  9075.  
  9076. var any =  this;
  9077. var node =  any;
  9078. WebInspector.TopDownProfileDataGridNode.prototype._exclude.call(node, excludedCallUID);
  9079.  
  9080. if (this.lastComparator)
  9081. this.sort(this.lastComparator, true);
  9082. },
  9083.  
  9084. restore: function()
  9085. {
  9086. if (!this._savedChildren)
  9087. return;
  9088.  
  9089. this.children[0].restorePosition();
  9090.  
  9091. WebInspector.ProfileDataGridTree.prototype.restore.call(this);
  9092. },
  9093.  
  9094. _merge: WebInspector.TopDownProfileDataGridNode.prototype._merge,
  9095.  
  9096. _sharedPopulate: WebInspector.TopDownProfileDataGridNode.prototype._sharedPopulate,
  9097.  
  9098. __proto__: WebInspector.ProfileDataGridTree.prototype
  9099. }
  9100. ;
  9101.  
  9102.  
  9103.  
  9104. WebInspector.CanvasProfileView = function(profile)
  9105. {
  9106. WebInspector.View.call(this);
  9107. this.registerRequiredCSS("canvasProfiler.css");
  9108. this._profile = profile;
  9109. this._traceLogId = profile.traceLogId();
  9110. this.element.addStyleClass("canvas-profile-view");
  9111.  
  9112. this._linkifier = new WebInspector.Linkifier();
  9113. this._splitView = new WebInspector.SplitView(false, "canvasProfileViewSplitLocation", 300);
  9114.  
  9115. var columns = { 0: {}, 1: {}, 2: {} };
  9116. columns[0].title = "#";
  9117. columns[0].sortable = true;
  9118. columns[0].width = "5%";
  9119. columns[1].title = WebInspector.UIString("Call");
  9120. columns[1].sortable = true;
  9121. columns[1].width = "75%";
  9122. columns[2].title = WebInspector.UIString("Location");
  9123. columns[2].sortable = true;
  9124. columns[2].width = "20%";
  9125.  
  9126. this._logGrid = new WebInspector.DataGrid(columns);
  9127. this._logGrid.element.addStyleClass("fill");
  9128. this._logGrid.show(this._splitView.secondElement());
  9129. this._logGrid.addEventListener(WebInspector.DataGrid.Events.SelectedNode, this._replayTraceLog.bind(this));
  9130.  
  9131. var replayImageContainer = this._splitView.firstElement();
  9132. replayImageContainer.id = "canvas-replay-image-container";
  9133.  
  9134. this._replayImageElement = document.createElement("image");
  9135. this._replayImageElement.id = "canvas-replay-image";
  9136.  
  9137. replayImageContainer.appendChild(this._replayImageElement);
  9138. this._debugInfoElement = document.createElement("div");
  9139. replayImageContainer.appendChild(this._debugInfoElement);
  9140.  
  9141. this._splitView.show(this.element);
  9142.  
  9143. this._enableWaitIcon(true);
  9144. CanvasAgent.getTraceLog(this._traceLogId, 0, this._didReceiveTraceLog.bind(this));
  9145. }
  9146.  
  9147. WebInspector.CanvasProfileView.prototype = {
  9148. dispose: function()
  9149. {
  9150. this._linkifier.reset();
  9151. CanvasAgent.dropTraceLog(this._traceLogId);
  9152. },
  9153.  
  9154. get statusBarItems()
  9155. {
  9156. return [];
  9157. },
  9158.  
  9159. get profile()
  9160. {
  9161. return this._profile;
  9162. },
  9163.  
  9164.  
  9165. elementsToRestoreScrollPositionsFor: function()
  9166. {
  9167. return [this._logGrid.scrollContainer];
  9168. },
  9169.  
  9170.  
  9171. _enableWaitIcon: function(enable)
  9172. {
  9173. function showWaitIcon()
  9174. {
  9175. this._replayImageElement.className = "wait";
  9176. this._debugInfoElement.textContent = "";
  9177. delete this._showWaitIconTimer;
  9178. }
  9179.  
  9180. if (enable && this._replayImageElement.src && !this._showWaitIconTimer)
  9181. this._showWaitIconTimer = setTimeout(showWaitIcon.bind(this), 250);
  9182. else {
  9183. if (this._showWaitIconTimer) {
  9184. clearTimeout(this._showWaitIconTimer);
  9185. delete this._showWaitIconTimer;
  9186. }
  9187. this._replayImageElement.className = enable ? "wait" : "";
  9188. this._debugInfoElement.textContent = "";
  9189. }
  9190. },
  9191.  
  9192. _replayTraceLog: function()
  9193. {
  9194. var callNode = this._logGrid.selectedNode;
  9195. if (!callNode)
  9196. return;
  9197. var time = Date.now();
  9198. function didReplayTraceLog(error, dataURL)
  9199. {
  9200. this._enableWaitIcon(false);
  9201. if (error)
  9202. return;
  9203. this._debugInfoElement.textContent = "Replay time: " + (Date.now() - time) + "ms";
  9204. this._replayImageElement.src = dataURL;
  9205. }
  9206. this._enableWaitIcon(true);
  9207. CanvasAgent.replayTraceLog(this._traceLogId, callNode.index, didReplayTraceLog.bind(this));
  9208. },
  9209.  
  9210. _didReceiveTraceLog: function(error, traceLog)
  9211. {
  9212. this._enableWaitIcon(false);
  9213. this._logGrid.rootNode().removeChildren();
  9214. if (error || !traceLog)
  9215. return;
  9216. var calls = traceLog.calls;
  9217. for (var i = 0, n = calls.length; i < n; ++i)
  9218. this._logGrid.rootNode().appendChild(this._createCallNode(i, calls[i]));
  9219. var lastNode = this._logGrid.rootNode().children[calls.length - 1];
  9220. if (lastNode) {
  9221. lastNode.reveal();
  9222. lastNode.select();
  9223. }
  9224. },
  9225.  
  9226. _createCallNode: function(index, call)
  9227. {
  9228. var traceLogItem = document.createElement("div");
  9229. var data = {};
  9230. data[0] = index + 1;
  9231. data[1] = call.functionName || "context." + call.property;
  9232. data[2] = "";
  9233. if (call.sourceURL) {
  9234.  
  9235. var lineNumber = Math.max(0, call.lineNumber - 1) || 0;
  9236. var columnNumber = Math.max(0, call.columnNumber - 1) || 0;
  9237. data[2] = this._linkifier.linkifyLocation(call.sourceURL, lineNumber, columnNumber);
  9238. }
  9239.  
  9240. if (call.arguments)
  9241. data[1] += "(" + call.arguments.join(", ") + ")";
  9242. else
  9243. data[1] += " = " + call.value;
  9244.  
  9245. if (typeof call.result !== "undefined")
  9246. data[1] += " => " + call.result;
  9247.  
  9248. var node = new WebInspector.DataGridNode(data);
  9249. node.call = call;
  9250. node.index = index;
  9251. node.selectable = true;
  9252. return node;
  9253. },
  9254.  
  9255. __proto__: WebInspector.View.prototype
  9256. }
  9257.  
  9258.  
  9259. WebInspector.CanvasProfileType = function()
  9260. {
  9261. WebInspector.ProfileType.call(this, WebInspector.CanvasProfileType.TypeId, WebInspector.UIString("Capture Canvas Frame"));
  9262. this._nextProfileUid = 1;
  9263.  
  9264. CanvasAgent.enable();
  9265. }
  9266.  
  9267. WebInspector.CanvasProfileType.TypeId = "CANVAS_PROFILE";
  9268.  
  9269. WebInspector.CanvasProfileType.prototype = {
  9270. get buttonTooltip()
  9271. {
  9272. return WebInspector.UIString("Capture Canvas Frame.");
  9273. },
  9274.  
  9275.  
  9276. buttonClicked: function(profilesPanel)
  9277. {
  9278. var profileHeader = new WebInspector.CanvasProfileHeader(this, WebInspector.UIString("Trace Log %d", this._nextProfileUid), this._nextProfileUid);
  9279. ++this._nextProfileUid;
  9280. profileHeader.isTemporary = true;
  9281. profilesPanel.addProfileHeader(profileHeader);
  9282. function didStartCapturingFrame(error, traceLogId)
  9283. {
  9284. profileHeader._traceLogId = traceLogId;
  9285. profileHeader.isTemporary = false;
  9286. }
  9287. CanvasAgent.captureFrame(didStartCapturingFrame.bind(this));
  9288. return false;
  9289. },
  9290.  
  9291. get treeItemTitle()
  9292. {
  9293. return WebInspector.UIString("CANVAS PROFILE");
  9294. },
  9295.  
  9296. get description()
  9297. {
  9298. return WebInspector.UIString("Canvas calls instrumentation");
  9299. },
  9300.  
  9301.  
  9302. reset: function()
  9303. {
  9304. this._nextProfileUid = 1;
  9305. },
  9306.  
  9307.  
  9308. createTemporaryProfile: function(title)
  9309. {
  9310. title = title || WebInspector.UIString("Capturing\u2026");
  9311. return new WebInspector.CanvasProfileHeader(this, title);
  9312. },
  9313.  
  9314.  
  9315. createProfile: function(profile)
  9316. {
  9317. return new WebInspector.CanvasProfileHeader(this, profile.title, -1);
  9318. },
  9319.  
  9320. __proto__: WebInspector.ProfileType.prototype
  9321. }
  9322.  
  9323.  
  9324. WebInspector.CanvasProfileHeader = function(type, title, uid)
  9325. {
  9326. WebInspector.ProfileHeader.call(this, type, title, uid);
  9327.  
  9328.  
  9329. this._traceLogId = null;
  9330. }
  9331.  
  9332. WebInspector.CanvasProfileHeader.prototype = {
  9333.  
  9334. traceLogId: function()
  9335. {
  9336. return this._traceLogId;
  9337. },
  9338.  
  9339.  
  9340. createSidebarTreeElement: function()
  9341. {
  9342. return new WebInspector.ProfileSidebarTreeElement(this, WebInspector.UIString("Trace Log %d"), "profile-sidebar-tree-item");
  9343. },
  9344.  
  9345.  
  9346. createView: function(profilesPanel)
  9347. {
  9348. return new WebInspector.CanvasProfileView(this);
  9349. },
  9350.  
  9351. __proto__: WebInspector.ProfileHeader.prototype
  9352. }
  9353. ;
  9354.